Je souhaite effacer un élément d'un vecteur en utilisant la méthode d'effacement. Mais le problème ici est que l'élément n'est pas garanti de se produire une seule fois dans le vecteur. Il peut être présent plusieurs fois et je dois tous les effacer. Mon code est quelque chose comme ceci:
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;
}
Ce code plante évidemment parce que je change la fin du vecteur en l'itérant. Quelle est la meilleure façon d'y parvenir? Existe-t-il un moyen de le faire sans itérer plusieurs fois dans le vecteur ou sans créer une copie supplémentaire du vecteur?
std::remove()
décale les éléments de sorte que les éléments à supprimer soient écrasés. L'algorithme ne change pas la taille du conteneur, et si desn
éléments sont supprimés, alors il est indéfini quels sont les derniersn
éléments.L'appel d'effacement invalidera les itérateurs, vous pouvez utiliser:
Ou vous pouvez utiliser std :: remove_if avec un foncteur et std :: vector :: erase:
Au lieu d'écrire votre propre foncteur dans ce cas, vous pouvez utiliser std :: remove :
En C ++ 11, vous pouvez utiliser un lambda au lieu d'un foncteur:
En C ++ 17, std :: experimental :: erase et std :: experimental :: erase_if sont également disponibles, en C ++ 20 ils sont (finalement) renommés en std :: erase et std :: erase_if :
ou:
la source
erase
avecremove
est le moyen canonique de le faire.Vous pouvez itérer en utilisant l'accès à l'index,
Pour éviter la complexité O (n ^ 2), vous pouvez utiliser deux indices, i - index de test actuel, j - index pour stocker l'élément suivant et à la fin du cycle, la nouvelle taille du vecteur.
code:
Dans ce cas, vous n'avez pas d'invalidation des itérateurs, la complexité est O (n) et le code est très concis et vous n'avez pas besoin d'écrire certaines classes d'assistance, bien que dans certains cas, l'utilisation de classes d'assistance peut bénéficier d'un code plus flexible.
Ce code n'utilise pas de
erase
méthode, mais résout votre tâche.En utilisant pure stl, vous pouvez le faire de la manière suivante (ceci est similaire à la réponse de Motti):
la source
Selon la raison pour laquelle vous faites cela, utiliser un std :: set peut être une meilleure idée que std :: vector.
Il permet à chaque élément de se produire une seule fois. Si vous l'ajoutez plusieurs fois, il n'y aura de toute façon qu'une seule instance à effacer. Cela rendra l'opération d'effacement triviale. L'opération d'effacement aura également une complexité temporelle plus faible que sur le vecteur, cependant, l'ajout d'éléments est plus lent sur l'ensemble, donc cela pourrait ne pas être un grand avantage.
Cela ne fonctionnera bien sûr pas si vous êtes intéressé par le nombre de fois qu'un élément a été ajouté à votre vecteur ou par l'ordre dans lequel les éléments ont été ajoutés.
la source
Pour effacer le 1er élément, vous pouvez utiliser:
la source