Considere usar um std :: deque que fornece inserção e exclusão nas duas extremidades.
Dario
40
Não, não considere usar o deque apenas porque você pode excluir um elemento, isso é um péssimo conselho. Existem várias razões pelas quais você pode querer usar deque ou vector. É verdade que excluir um elemento de um vetor pode ser caro - especialmente se o vetor for grande, mas não há razão para pensar que um deque seria melhor do que um vetor do exemplo de código que você acabou de postar.
coruja
6
Por exemplo, se você tem um aplicativo gráfico no qual exibe uma "lista" de itens em que você insere / remove itens interativamente, considere percorrer a lista de 50 a 100 vezes por segundo para exibi-los e adicione / remova alguns itens vezes a cada minuto. Portanto, implementar a "lista" como vetor provavelmente é uma opção melhor em termos de eficiência total.
Michel Billaud
Respostas:
705
Para excluir um único elemento, você pode fazer:
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);
Ou, para excluir mais de um elemento de uma vez:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin()+1, vec.begin()+3);
Observe também que binário nãooperator+ é necessariamente definido para iteradores em outros tipos de contêiner, como (você não pode fazer em um , você deve usarlist<T>::iteratorlist.begin() + 2std::liststd::advance para isso)
bobobobo
você está afirmando que o "+1" é o primeiro elemento myVector [0] ou a posição real myVector [1]
K - A toxicidade no SO está aumentando.
2
Com antecedência, você deve salvar o iterador em uma variável. Se você usar std :: next, poderá fazê-lo em uma linha: vec.erase (next (begin (vec), 123));
Dani #
8
Obrigado a todos que responderam. O que devemos pensar em um design de classe quando uma operação tão simples como excluir um elemento exige que você chegue ao StackOverflow?
Pierre
5
@ Pierre porque o índice numérico de um elemento em particular não é o modelo principal de acesso, é o iterador . Todas as funções que examinam os elementos de um contêiner usam os iteradores desse contêiner. Por exemplostd::find_if
Caleth 03/07
212
O método erase no std :: vector está sobrecarregado, por isso é provavelmente mais claro chamar
vec.erase(vec.begin()+ index);
quando você deseja apagar apenas um único elemento.
Mas esse problema aparece, não importa quantos elementos você tenha.
Zyx 2000
15
se houver apenas um elemento, o índice é 0 e, portanto, você obtém vec.begin()qual é válido.
Anne Quinn
28
Eu gostaria que alguém tivesse mencionado que vec.erase(0)não funciona, mas vec.erase(vec.begin()+0)(ou sem +0) funciona. Caso contrário, eu não obter chamada de função correspondente, que é por isso que vim aqui
qrtLs
@qrtLs vec.erase(0)pode realmente compilar se 0passa a ser interpretada como a constante ponteiro nulo ...
Max, o que torna essa função melhor do que: template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }eu não estou dizendo que qualquer uma é melhor, apenas pedindo por interesse pessoal e retornar o melhor resultado que essa pergunta poderia obter.
13
@ JoeyvG: Como a vector<T>::iteratoré um iterador de acesso aleatório, sua versão é boa e talvez um pouco mais clara. Mas a versão que Max postou deve funcionar muito bem se você alterar o recipiente para um outro que não suporta iteradores de acesso aleatório
Lily Ballard
2
Essa é a melhor resposta, pois também se aplica a outros formatos de contêiner. Você também pode usar std :: next ().
Bim
Abordagem muito melhor, pois não depende das partes internas do contêiner.
BartoszKP
std :: advance é necessário apenas se você achar que este não será um vetor, ou seja, uma lista. Mas como você especificou isso aqui, o operador + não seria mais simples? De acordo com este stackoverflow.com/questions/1668088/… , é possível um ganho de desempenho com o operador +
Neil McGill
14
O erasemétodo será usado de duas maneiras:
Apagando um único elemento:
vector.erase( vector.begin()+3);// Deleting the fourth element
Apagando vários elementos:
vector.erase( vector.begin()+3, vector.begin()+5);// Deleting from fourth element to sixth element
Esta é uma resposta duplicada quase 7 anos após a resposta aceita. Por favor, não faça isso.
AlastairG
10
Na verdade, a erasefunção funciona para dois perfis:
Removendo um Único Elemento
iterator erase (iterator position);
Removendo uma variedade de elementos
iterator erase (iterator first, iterator last);
Como std :: vec.begin () marca o início do contêiner e, se quisermos excluir o i-ésimo elemento em nosso vetor, podemos usar:
vec.erase(vec.begin()+ index);
Se você observar atentamente, vec.begin () é apenas um ponteiro para a posição inicial do nosso vetor e, ao adicionar o valor de i, ele aumenta o ponteiro para a posição i; portanto, podemos acessar o ponteiro para o i-ésimo elemento:
-1 A última linha não é compilada (pelo menos no VS2017). O código assume que vector :: iterator é implicitamente construtível a partir de um ponteiro bruto, o que não é exigido pelo padrão.
CuriousGeorge
1
Isto é verdade especialmente para iterators depuração
Nishant Singh
9
Se você tem um vetor não ordenado, pode aproveitar o fato de ele não ser ordenado e usar algo que vi de Dan Higgins no CPPCON
Como a ordem da lista não importa, basta pegar o último elemento da lista e copiá-lo por cima do item que você deseja remover, em seguida, pop e exclua o último item.
Eu acho que essa é a melhor resposta se o vetor não for ordenado. Ele não se baseia na suposição de que iterator + indexvocê retornará a posição do iterador nesse índice, o que não é verdade para todos os contêineres iteráveis. Também é uma complexidade constante, em vez de linear, aproveitando o ponteiro de trás.
theferrit32
1
Isso precisa ser totalmente adicionado à lib std como unordered_removee unordered_remove_if… a menos que tenha sido e eu perdi, o que está acontecendo com mais frequência hoje em dia :)
Will Crawford
Se sugeriria usar atribuição de movimento ou troca em vez de uma atribuição de cópia.
Carsten S
std::removereordena o contêiner para que todos os elementos a serem removidos estejam no final, não é necessário fazê-lo manualmente dessa maneira, se você estiver usando o C ++ 17.
keith
@keith como std::removeajuda? A cppreference afirma que, mesmo no C ++ 17, todas as removesobrecargas exigem um predicado e nenhuma recebe um índice.
Paul Du Bois
4
Se você trabalha com vetores grandes (tamanho> 100.000) e deseja excluir muitos elementos, eu recomendaria fazer algo assim:
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;}
O código pega todos os números no vec que não podem ser divididos por 3 e o copia no vec2. Depois, copia o vec2 no vec. É bem rápido. Para processar 20.000.000 de elementos, esse algoritmo leva apenas 0,8 s!
Fiz a mesma coisa com o método erase, e leva muito e muito tempo:
você apagará o n-ésimo elemento do vetor, mas quando você apagar o segundo elemento, todos os outros elementos do vetor serão deslocados e o tamanho do vetor será -1. Isso pode ser um problema se você percorrer o vetor, pois o tamanho do vetor () está diminuindo. Se você tiver um problema como este, o link fornecido sugere o uso do algoritmo existente na biblioteca C ++ padrão. e "remover" ou "remover_se".
As respostas anteriores assumem que você sempre tem um índice assinado. Infelizmente, std::vectorusa size_typepara indexação e difference_typearitmética do iterador, para que não funcionem juntos se você tiver "-Wconversion" e amigos ativados. Esta é outra maneira de responder à pergunta, enquanto é capaz de lidar com assinados e não assinados:
Respostas:
Para excluir um único elemento, você pode fazer:
Ou, para excluir mais de um elemento de uma vez:
fonte
operator+
é necessariamente definido para iteradores em outros tipos de contêiner, como (você não pode fazer em um , você deve usarlist<T>::iterator
list.begin() + 2
std::list
std::advance
para isso)std::find_if
O método erase no std :: vector está sobrecarregado, por isso é provavelmente mais claro chamar
quando você deseja apagar apenas um único elemento.
fonte
vec.begin()
qual é válido.vec.erase(0)
não funciona, masvec.erase(vec.begin()+0)
(ou sem +0) funciona. Caso contrário, eu não obter chamada de função correspondente, que é por isso que vim aquivec.erase(0)
pode realmente compilar se0
passa a ser interpretada como a constante ponteiro nulo ...fonte
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
eu não estou dizendo que qualquer uma é melhor, apenas pedindo por interesse pessoal e retornar o melhor resultado que essa pergunta poderia obter.vector<T>::iterator
é um iterador de acesso aleatório, sua versão é boa e talvez um pouco mais clara. Mas a versão que Max postou deve funcionar muito bem se você alterar o recipiente para um outro que não suporta iteradores de acesso aleatórioO
erase
método será usado de duas maneiras:Apagando um único elemento:
Apagando vários elementos:
fonte
Na verdade, a
erase
função funciona para dois perfis:Removendo um Único Elemento
Removendo uma variedade de elementos
Como std :: vec.begin () marca o início do contêiner e, se quisermos excluir o i-ésimo elemento em nosso vetor, podemos usar:
Se você observar atentamente, vec.begin () é apenas um ponteiro para a posição inicial do nosso vetor e, ao adicionar o valor de i, ele aumenta o ponteiro para a posição i; portanto, podemos acessar o ponteiro para o i-ésimo elemento:
Para que possamos escrever:
fonte
Se você tem um vetor não ordenado, pode aproveitar o fato de ele não ser ordenado e usar algo que vi de Dan Higgins no CPPCON
Como a ordem da lista não importa, basta pegar o último elemento da lista e copiá-lo por cima do item que você deseja remover, em seguida, pop e exclua o último item.
fonte
iterator + index
você retornará a posição do iterador nesse índice, o que não é verdade para todos os contêineres iteráveis. Também é uma complexidade constante, em vez de linear, aproveitando o ponteiro de trás.unordered_remove
eunordered_remove_if
… a menos que tenha sido e eu perdi, o que está acontecendo com mais frequência hoje em dia :)std::remove
reordena o contêiner para que todos os elementos a serem removidos estejam no final, não é necessário fazê-lo manualmente dessa maneira, se você estiver usando o C ++ 17.std::remove
ajuda? A cppreference afirma que, mesmo no C ++ 17, todas asremove
sobrecargas exigem um predicado e nenhuma recebe um índice.Se você trabalha com vetores grandes (tamanho> 100.000) e deseja excluir muitos elementos, eu recomendaria fazer algo assim:
O código pega todos os números no vec que não podem ser divididos por 3 e o copia no vec2. Depois, copia o vec2 no vec. É bem rápido. Para processar 20.000.000 de elementos, esse algoritmo leva apenas 0,8 s!
Fiz a mesma coisa com o método erase, e leva muito e muito tempo:
fonte
Para excluir um elemento, use o seguinte caminho:
Para uma visão mais ampla visite: http://www.cplusplus.com/reference/vector/vector/erase/
fonte
Sugiro ler isso, pois acredito que é isso que você está procurando.https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
Se você usa por exemplo
você apagará o n-ésimo elemento do vetor, mas quando você apagar o segundo elemento, todos os outros elementos do vetor serão deslocados e o tamanho do vetor será -1. Isso pode ser um problema se você percorrer o vetor, pois o tamanho do vetor () está diminuindo. Se você tiver um problema como este, o link fornecido sugere o uso do algoritmo existente na biblioteca C ++ padrão. e "remover" ou "remover_se".
Espero que isso tenha ajudado
fonte
As respostas anteriores assumem que você sempre tem um índice assinado. Infelizmente,
std::vector
usasize_type
para indexação edifference_type
aritmética do iterador, para que não funcionem juntos se você tiver "-Wconversion" e amigos ativados. Esta é outra maneira de responder à pergunta, enquanto é capaz de lidar com assinados e não assinados:Remover:
Pegar:
fonte
aqui está mais uma maneira de fazer isso, se você deseja excluir um elemento encontrando-o com seu valor em vetor, basta fazer isso em vetor.
isso removerá seu valor daqui. obrigado
fonte
Que tal agora?
fonte
o caminho mais rápido (para programação de concursos por complexidade de tempo () = constante)
pode apagar 100 milhões de itens em 1 segundo;
e maneira mais legível:
vec.erase(vec.begin() + pos);
fonte
vector<int>::iterator
não é necessariamente o mesmo queint *