Considere usar un std :: deque que proporciona inserción y eliminación en ambos extremos.
Dario
40
No, no considere usar deque solo porque desee eliminar un elemento, eso es realmente un mal consejo. Hay una gran cantidad de razones por las que es posible que desee utilizar deque o vector. Es cierto que eliminar un elemento de un vector puede ser costoso, especialmente si el vector es grande, pero no hay razón para pensar que una eliminación sería mejor que un vector del ejemplo de código que acaba de publicar.
Owl
66
Por ejemplo, si tiene una aplicación gráfica en la que muestra una "lista" de cosas donde inserta / elimina cosas de forma interactiva, considere que recorre la lista 50-100 veces por segundo para mostrarlas, y agrega / elimina algunas cosas veces cada minuto. Por lo tanto, implementar la "lista" como un vector es probablemente una mejor opción en términos de eficiencia total.
Michel Billaud
Respuestas:
706
Para eliminar un solo elemento, puede hacer:
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);
O, para eliminar más de un elemento a la vez:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin()+1, vec.begin()+3);
Tenga en cuenta que el binario nooperator+ está necesariamente definido para iteradores en otros tipos de contenedores, como (no puede hacerlo en un , debe usar para eso)list<T>::iteratorlist.begin() + 2std::liststd::advance
bobobobo
¿Está diciendo que "+1" es el primer elemento myVector [0] o la posición real myVector [1]
K - La toxicidad en SO está creciendo.
2
Con anticipación, debe guardar el iterador en una variable. Si usa std :: next puede hacerlo en una línea: vec.erase (next (begin (vec), 123));
dani
8
Gracias a todos los que respondieron. ¿Qué debemos pensar de un diseño de clase cuando una operación tan simple como eliminar un elemento requiere que uno venga a StackOverflow?
Pierre
55
@Pierre porque el índice numérico de un elemento en particular no es el modelo principal de acceso, sí lo es el iterador . Todas las funciones que miran los elementos de un contenedor utilizan los iteradores de ese contenedor. Por ejemplostd::find_if
Caleth
212
El método de borrado en std :: vector está sobrecargado, por lo que probablemente sea más claro llamar
Pero ese problema aparece sin importar cuántos elementos tenga.
Zyx 2000
15
si solo hay un elemento, el índice es 0, y así obtienes vec.begin()cuál es válido.
Anne Quinn el
28
Desearía que alguien hubiera mencionado que vec.erase(0)no funciona, pero vec.erase(vec.begin()+0)(o sin +0) sí. De lo contrario, no recibo una llamada de función coincidente, por eso vine aquí
qrtLs
@qrtLs en vec.erase(0)realidad puede compilarse si 0se interpreta como la constante de puntero nulo ...
Max, lo que hace que esa función sea mejor que: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }No estoy diciendo que ninguno sea mejor, simplemente preguntando por interés personal y para devolver el mejor resultado que esta pregunta podría obtener.
13
@JoeyvG: Dado que a vector<T>::iteratores un iterador de acceso aleatorio, su versión está bien y quizás un poco más clara. Pero la versión que publicó Max debería funcionar bien si cambia el contenedor a otro que no sea compatible con iteradores de acceso aleatorio
Lily Ballard
2
Esta es la mejor respuesta, ya que también se aplica a otros formatos de contenedor. También puede usar std :: next ().
Bim
Enfoque mucho mejor ya que no depende de la parte interna del contenedor.
BartoszKP
std :: advance solo es necesario si cree que esto no será un vector, es decir, una lista. Pero como lo ha especificado aquí, ¿operador + no sería más simple? De acuerdo a esto stackoverflow.com/questions/1668088/... hay una posible ganancia en el rendimiento con el operador +
Neil McGill
14
El erasemétodo se usará de dos maneras:
Borrar un solo elemento:
vector.erase( vector.begin()+3);// Deleting the fourth element
Borrado de rango de elementos:
vector.erase( vector.begin()+3, vector.begin()+5);// Deleting from fourth element to sixth element
Esta es una respuesta duplicada casi 7 años después de la respuesta aceptada. Por favor no hagas esto.
AlastairG
10
En realidad, la erasefunción funciona para dos perfiles:
Eliminar un solo elemento
iterator erase (iterator position);
Eliminar una gama de elementos
iterator erase (iterator first, iterator last);
Dado que std :: vec.begin () marca el inicio del contenedor y si queremos eliminar el elemento i-ésimo en nuestro vector, podemos usar:
vec.erase(vec.begin()+ index);
Si observa de cerca, vec.begin () es solo un puntero a la posición inicial de nuestro vector y al agregarle el valor de i incrementa el puntero a la posición i, por lo que podemos acceder al puntero al elemento i-ésimo de la siguiente manera:
-1 La última línea no se compila (al menos en VS2017). El código asume que vector :: iterator es implícitamente construible a partir de un puntero sin procesar, que no es requerido por el estándar.
CuriousGeorge
1
Esto es cierto especialmente para los iteradores de depuración
Nishant Singh
9
Si tiene un vector desordenado, puede aprovechar el hecho de que está desordenado y usar algo que vi de Dan Higgins en CPPCON
Como el orden de la lista no importa, solo tome el último elemento de la lista y cópielo sobre la parte superior del elemento que desea eliminar, luego haga estallar y elimine el último elemento.
Creo que esta es la mejor respuesta si el vector no está ordenado. No se basa en el supuesto de que iterator + indexrealmente le devolverá la posición del iterador en ese índice, lo que no es cierto para todos los contenedores iterables. También es una complejidad constante en lugar de lineal al aprovechar el puntero posterior.
theferrit32
1
Esto debe agregarse totalmente a la biblioteca estándar como unordered_removey unordered_remove_if... a menos que lo haya sido y lo haya extrañado, lo que sucede cada vez más a menudo en estos días :)
Will Crawford
Sugeriría usar mover-asignación o intercambio en lugar de una copia-asignación.
Carsten S
std::removereordena el contenedor para que todos los elementos que se eliminarán estén al final, no es necesario hacerlo manualmente si está usando C ++ 17.
keith
@keith ¿cómo std::removeayuda? cppreference afirma que incluso en C ++ 17, todas las removesobrecargas requieren un predicado y ninguna toma un índice.
Paul Du Bois
4
Si trabaja con vectores grandes (tamaño> 100,000) y desea eliminar muchos elementos, le recomendaría hacer algo como esto:
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;}
El código toma cada número en vec que no se puede dividir entre 3 y lo copia en vec2. Luego copia vec2 en vec. Es bastante rápido ¡Para procesar 20,000,000 elementos, este algoritmo solo toma 0.8 segundos!
Hice lo mismo con el método de borrado, y lleva mucho, mucho tiempo:
borrará el enésimo elemento del vector, pero cuando borre el segundo elemento, todos los demás elementos del vector se desplazarán y el tamaño del vector será -1. Esto puede ser un problema si recorre el vector ya que el tamaño del vector () está disminuyendo. Si tiene un problema como este, el enlace proporcionado sugiere utilizar el algoritmo existente en la biblioteca estándar de C ++. y "eliminar" o "eliminar_si".
Las respuestas anteriores suponen que siempre tiene un índice firmado. Lamentablemente, los std::vectorusos size_typepara la indexación, ydifference_type aritmética de iteradores, por lo que no funcionan juntos si tiene "-Wconversion" y amigos habilitados. Esta es otra forma de responder la pregunta, al tiempo que puede manejar tanto con signo como sin signo:
Respuestas:
Para eliminar un solo elemento, puede hacer:
O, para eliminar más de un elemento a la vez:
fuente
operator+
está necesariamente definido para iteradores en otros tipos de contenedores, como (no puede hacerlo en un , debe usar para eso)list<T>::iterator
list.begin() + 2
std::list
std::advance
std::find_if
El método de borrado en std :: vector está sobrecargado, por lo que probablemente sea más claro llamar
cuando solo quieres borrar un solo elemento.
fuente
vec.begin()
cuál es válido.vec.erase(0)
no funciona, perovec.erase(vec.begin()+0)
(o sin +0) sí. De lo contrario, no recibo una llamada de función coincidente, por eso vine aquívec.erase(0)
realidad puede compilarse si0
se interpreta como la constante de puntero nulo ...fuente
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
No estoy diciendo que ninguno sea mejor, simplemente preguntando por interés personal y para devolver el mejor resultado que esta pregunta podría obtener.vector<T>::iterator
es un iterador de acceso aleatorio, su versión está bien y quizás un poco más clara. Pero la versión que publicó Max debería funcionar bien si cambia el contenedor a otro que no sea compatible con iteradores de acceso aleatorioEl
erase
método se usará de dos maneras:Borrar un solo elemento:
Borrado de rango de elementos:
fuente
En realidad, la
erase
función funciona para dos perfiles:Eliminar un solo elemento
Eliminar una gama de elementos
Dado que std :: vec.begin () marca el inicio del contenedor y si queremos eliminar el elemento i-ésimo en nuestro vector, podemos usar:
Si observa de cerca, vec.begin () es solo un puntero a la posición inicial de nuestro vector y al agregarle el valor de i incrementa el puntero a la posición i, por lo que podemos acceder al puntero al elemento i-ésimo de la siguiente manera:
Entonces podemos escribir:
fuente
Si tiene un vector desordenado, puede aprovechar el hecho de que está desordenado y usar algo que vi de Dan Higgins en CPPCON
Como el orden de la lista no importa, solo tome el último elemento de la lista y cópielo sobre la parte superior del elemento que desea eliminar, luego haga estallar y elimine el último elemento.
fuente
iterator + index
realmente le devolverá la posición del iterador en ese índice, lo que no es cierto para todos los contenedores iterables. También es una complejidad constante en lugar de lineal al aprovechar el puntero posterior.unordered_remove
yunordered_remove_if
... a menos que lo haya sido y lo haya extrañado, lo que sucede cada vez más a menudo en estos días :)std::remove
reordena el contenedor para que todos los elementos que se eliminarán estén al final, no es necesario hacerlo manualmente si está usando C ++ 17.std::remove
ayuda? cppreference afirma que incluso en C ++ 17, todas lasremove
sobrecargas requieren un predicado y ninguna toma un índice.Si trabaja con vectores grandes (tamaño> 100,000) y desea eliminar muchos elementos, le recomendaría hacer algo como esto:
El código toma cada número en vec que no se puede dividir entre 3 y lo copia en vec2. Luego copia vec2 en vec. Es bastante rápido ¡Para procesar 20,000,000 elementos, este algoritmo solo toma 0.8 segundos!
Hice lo mismo con el método de borrado, y lleva mucho, mucho tiempo:
fuente
Para eliminar un elemento, use la siguiente manera:
Para obtener una descripción más amplia , puede visitar: http://www.cplusplus.com/reference/vector/vector/erase/
fuente
Sugiero leer esto ya que creo que eso es lo que estás buscando. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Si usas por ejemplo
borrará el enésimo elemento del vector, pero cuando borre el segundo elemento, todos los demás elementos del vector se desplazarán y el tamaño del vector será -1. Esto puede ser un problema si recorre el vector ya que el tamaño del vector () está disminuyendo. Si tiene un problema como este, el enlace proporcionado sugiere utilizar el algoritmo existente en la biblioteca estándar de C ++. y "eliminar" o "eliminar_si".
Espero que esto haya ayudado
fuente
Las respuestas anteriores suponen que siempre tiene un índice firmado. Lamentablemente, los
std::vector
usossize_type
para la indexación, ydifference_type
aritmética de iteradores, por lo que no funcionan juntos si tiene "-Wconversion" y amigos habilitados. Esta es otra forma de responder la pregunta, al tiempo que puede manejar tanto con signo como sin signo:Para eliminar:
Tomar:
fuente
Aquí hay una forma más de hacer esto si desea eliminar un elemento encontrando esto con su valor en vector, solo necesita hacer esto en vector.
eliminará tu valor de aquí. Gracias
fuente
¿Qué tal esto?
fuente
la forma más rápida (para programar concursos por complejidad de tiempo () = constante)
puede borrar un elemento de 100M en 1 segundo;
y la forma más legible:
vec.erase(vec.begin() + pos);
fuente
vector<int>::iterator
no es necesariamente lo mismo queint *