it-swarm.com.de

Elemente aus einem Vektor löschen

Ich möchte ein Element mit der Löschmethode aus einem Vektor löschen. Das Problem hierbei ist jedoch, dass nicht garantiert wird, dass das Element nur einmal im Vektor auftritt. Es kann mehrere Male vorhanden sein und ich muss alle von ihnen löschen. Mein Code sieht ungefähr so ​​aus:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
    std::vector<int>::iterator iter = myNumbers_in.begin();
    std::vector<int>::iterator endIter = myNumbers_in.end();
    for(; iter != endIter; ++iter)
    {
        if(*iter == number_in)
        {
            myNumbers_in.erase(iter);
        }
    }
}

int main(int argc, char* argv[])
{
    std::vector<int> myNmbers;
    for(int i = 0; i < 2; ++i)
    {
        myNmbers.Push_back(i);
        myNmbers.Push_back(i);
    }

    erase(myNmbers, 1);

    return 0;
}

Dieser Code stürzt offensichtlich ab, weil ich das Ende des Vektors ändere, während ich ihn durchlaufe. Was ist der beste Weg, um dies zu erreichen? Das heißt Gibt es eine Möglichkeit, dies zu tun, ohne den Vektor mehrmals zu durchlaufen oder eine weitere Kopie des Vektors zu erstellen?

91
Naveen

Verwenden Sie das Entfernen/Löschen-Idiom :

std::vector<int>& vec = myNumbers; // use shorter name
vec.erase(std::remove(vec.begin(), vec.end(), number_in), vec.end());

Was passiert ist, dass remove die Elemente komprimiert, die vom zu entfernenden Wert abweichen (number_in) am Anfang von vector und gibt den Iterator an das erste Element nach diesem Bereich zurück. Dann entfernt erase diese Elemente (dessen Wert nicht angegeben ist).

148
Motti

Wenn Sie erase aufrufen, werden die Iteratoren ungültig. Sie können Folgendes verwenden:

void erase(std::vector<int>& myNumbers_in, int number_in)
{
    std::vector<int>::iterator iter = myNumbers_in.begin();
    while (iter != myNumbers_in.end())
    {
        if (*iter == number_in)
        {
            iter = myNumbers_in.erase(iter);
        }
        else
        {
           ++iter;
        }
    }

}

Oder Sie können std :: remove_if zusammen mit einem Funktor und std :: vector :: erase verwenden:

struct Eraser
{
    Eraser(int number_in) : number_in(number_in) {}
    int number_in;
    bool operator()(int i) const
    {
        return i == number_in;
    }
};

std::vector<int> myNumbers;
myNumbers.erase(std::remove_if(myNumbers.begin(), myNumbers.end(), Eraser(number_in)), myNumbers.end());

Anstatt in diesem Fall Ihren eigenen Funktor zu schreiben, können Sie auch std :: remove verwenden:

std::vector<int> myNumbers;
myNumbers.erase(std::remove(myNumbers.begin(), myNumbers.end(), number_in), myNumbers.end());
47
dalle
  1. Sie können mit dem Indexzugriff iterieren,

  2. Um die Komplexität von O (n ^ 2) zu vermeiden, können Sie zwei Indizes verwenden: i - aktueller Testindex, j - Index zum Speichern des nächsten Elements und am Ende des Zyklus die neue Größe des Vektors.

code:

void erase(std::vector<int>& v, int num)
{
  size_t j = 0;
  for (size_t i = 0; i < v.size(); ++i) {
    if (v[i] != num) v[j++] = v[i];
  }
  // trim vector to new size
  v.resize(j);
}

In diesem Fall werden keine Iteratoren ungültig gemacht, die Komplexität ist O (n), und der Code ist sehr kurz und Sie müssen keine Hilfsklassen schreiben, obwohl in einigen Fällen die Verwendung von Hilfsklassen in flexiblerem Code von Vorteil sein kann.

Dieser Code verwendet nicht die Methode erase, sondern löst Ihre Aufgabe.

Mit pure stl können Sie dies auf folgende Weise tun (dies ähnelt der Antwort von Motti):

#include <algorithm>

void erase(std::vector<int>& v, int num) {
    vector<int>::iterator it = remove(v.begin(), v.end(), num);
    v.erase(it, v.end());
}
12
sergtk

Je nachdem, warum Sie dies tun, ist die Verwendung von std :: set möglicherweise eine bessere Idee als std :: vector.

Jedes Element darf nur einmal vorkommen. Wenn Sie es mehrmals hinzufügen, muss ohnehin nur eine Instanz gelöscht werden. Dies macht den Löschvorgang trivial. Die Löschoperation hat auch eine geringere zeitliche Komplexität als der Vektor, jedoch ist das Hinzufügen von Elementen am Satz langsamer, so dass dies möglicherweise kein großer Vorteil ist.

Dies funktioniert natürlich nicht, wenn Sie daran interessiert sind, wie oft ein Element zu Ihrem Vektor hinzugefügt wurde oder in welcher Reihenfolge die Elemente hinzugefügt wurden.

3
Laserallan