Ich habe einen std :: vector <int> und möchte das n-te Element löschen. Wie mache ich das?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Ich habe einen std :: vector <int> und möchte das n-te Element löschen. Wie mache ich das?
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
Antworten:
Um ein einzelnes Element zu löschen, haben Sie folgende Möglichkeiten:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);
Oder um mehrere Elemente gleichzeitig zu löschen:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);
operator+
ist nicht unbedingt für Iteratoren auf andere Behältertypen definiert, wie list<T>::iterator
(Sie nicht tun können list.begin() + 2
auf ein std::list
, den Sie verwenden müssen std::advance
für diese)
std::find_if
Die Löschmethode für std :: vector ist überladen, daher ist der Aufruf wahrscheinlich klarer
vec.erase(vec.begin() + index);
wenn Sie nur ein einzelnes Element löschen möchten.
vec.begin()
welches gültig ist.
vec.erase(0)
dies nicht funktioniert, aber vec.erase(vec.begin()+0)
(oder ohne +0). Ansonsten bekomme ich keinen passenden Funktionsaufruf, weshalb ich hierher
vec.erase(0)
kann tatsächlich kompiliert werden, wenn es 0
zufällig als Nullzeigerkonstante interpretiert wird ...
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
Ich sage auch nicht, dass es besser ist, nur aus persönlichem Interesse zu fragen und das beste Ergebnis zu erzielen, das diese Frage erzielen könnte.
vector<T>::iterator
ein Iterator mit wahlfreiem Zugriff ist, ist Ihre Version in Ordnung und möglicherweise etwas klarer. Aber die Version, die Max gepostet hat, sollte gut funktionieren, wenn Sie den Container in einen anderen ändern, der keine Iteratoren mit wahlfreiem Zugriff unterstützt
Die erase
Methode wird auf zwei Arten verwendet:
Einzelelement löschen:
vector.erase( vector.begin() + 3 ); // Deleting the fourth element
Löschen einer Reihe von Elementen:
vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element
Tatsächlich erase
funktioniert die Funktion für zwei Profile:
Ein einzelnes Element entfernen
iterator erase (iterator position);
Eine Reihe von Elementen entfernen
iterator erase (iterator first, iterator last);
Da std :: vec.begin () den Beginn des Containers markiert und wir das i-te Element in unserem Vektor löschen möchten, können wir Folgendes verwenden:
vec.erase(vec.begin() + index);
Wenn Sie genau hinschauen, ist vec.begin () nur ein Zeiger auf die Startposition unseres Vektors. Wenn Sie den Wert von i hinzufügen, wird der Zeiger auf die Position i erhöht, sodass wir stattdessen auf den Zeiger auf das i-te Element zugreifen können, indem:
&vec[i]
So können wir schreiben:
vec.erase(&vec[i]); // To delete the ith element
Wenn Sie einen ungeordneten Vektor haben, können Sie die Tatsache nutzen, dass er ungeordnet ist, und etwas verwenden, das ich von Dan Higgins bei CPPCON gesehen habe
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
Da die Listenreihenfolge keine Rolle spielt, nehmen Sie einfach das letzte Element in der Liste und kopieren Sie es über das Element, das Sie entfernen möchten. Fügen Sie dann das letzte Element hinzu und löschen Sie es.
iterator + index
basiert nicht auf der Annahme, dass Sie tatsächlich die Iteratorposition an diesem Index zurückgeben, was nicht für alle iterierbaren Container gilt. Es ist auch eine konstante Komplexität anstelle einer linearen, indem der Rückzeiger ausgenutzt wird.
unordered_remove
und unordered_remove_if
… es sei denn, es wurde und ich habe es verpasst, was heutzutage immer häufiger vorkommt :)
std::remove
Ordnet den Container so an, dass alle zu entfernenden Elemente am Ende sind. Wenn Sie C ++ 17 verwenden, müssen Sie dies nicht manuell tun.
std::remove
hilft das? cppreference behauptet, dass selbst in C ++ 17 alle remove
Überladungen ein Prädikat erfordern und keine einen Index annehmen.
Wenn Sie mit großen Vektoren (Größe> 100.000) arbeiten und viele Elemente löschen möchten, würde ich Folgendes empfehlen:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
Der Code nimmt jede Zahl in vec, die nicht durch 3 geteilt werden kann, und kopiert sie in vec2. Danach kopiert es vec2 in vec. Es ist ziemlich schnell. Um 20.000.000 Elemente zu verarbeiten, benötigt dieser Algorithmus nur 0,8 Sekunden!
Ich habe das gleiche mit der Löschmethode gemacht, und es dauert sehr viel Zeit:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
Gehen Sie folgendermaßen vor, um ein Element zu löschen:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
Eine umfassendere Übersicht finden Sie unter: http://www.cplusplus.com/reference/vector/vector/erase/
Ich schlage vor, dies zu lesen, da ich glaube, dass Sie danach suchen. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Wenn Sie zum Beispiel verwenden
vec.erase(vec.begin() + 1, vec.begin() + 3);
Sie löschen das n-te Element des Vektors, aber wenn Sie das zweite Element löschen, werden alle anderen Elemente des Vektors verschoben und die Vektorgröße beträgt -1. Dies kann problematisch sein, wenn Sie den Vektor durchlaufen, da die Vektorgröße () abnimmt. Wenn Sie ein Problem wie dieses haben, wird der Link empfohlen, den vorhandenen Algorithmus in der Standard-C ++ - Bibliothek zu verwenden. und "remove" oder "remove_if".
Hoffe das hat geholfen
Die vorherigen Antworten setzen voraus, dass Sie immer einen signierten Index haben. Leider std::vector
Anwendungen size_type
für die Indizierung und difference_type
für Iterator Arithmetik, so dass sie arbeiten nicht zusammen , wenn Sie „-Wconversion“ haben und Freunde aktiviert. Dies ist eine weitere Möglichkeit, die Frage zu beantworten und gleichzeitig sowohl signierte als auch nicht signierte zu verarbeiten:
Zu entfernen:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
Nehmen:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
Hier ist eine weitere Möglichkeit, dies zu tun, wenn Sie ein Element löschen möchten, indem Sie dies mit seinem Wert im Vektor finden. Sie müssen dies nur für den Vektor tun.
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
es wird Ihren Wert von hier entfernen. Vielen Dank
der schnellste Weg (zum Programmieren von Wettbewerben nach Zeitkomplexität () = konstant)
kann 100 Millionen Objekte in 1 Sekunde löschen;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
und am besten lesbarer Weg:
vec.erase(vec.begin() + pos);
vector<int>::iterator
ist nicht unbedingt das gleiche wieint *