J'ai lu que la complexité temporelle de l'ajout d'éléments à la fin d'un std::vector
Est constante et que l'insertion d'éléments en haut et en bas d'un std::deque
Est constante. Puisque ces deux conteneurs ont un itérateur d'accès aléatoire ainsi l'accès aux éléments à n'importe quel index est constant. S'il vous plaît laissez-moi savoir si j'ai un de ces faits faux.Ma question est de savoir si l'accès à un élément dans un std::vector
Ou std::deque
Est constant, alors pourquoi la complexité temporelle de la suppression d'un élément via l'effacement O (n). L'une des réponses ici indique ici que la suppression d'éléments via l'effacement est O (n). Je sais que l'effacement supprime les éléments entre les itérateurs de début et de fin, de même que la réponse signifie essentiellement que sa O(n)
en fonction du nombre d'éléments entre les deux itérateurs et que la suppression d'un seul élément d'un vecteur/deque dans tout indice sera nul?
Les choses sont un peu différentes pour std::vector
Et std::deque
, Ainsi que pour C++ 98 et C++ 11.
La complexité de std::vector::erase()
est linéaire à la fois par la longueur de la plage effacée et par le nombre d'éléments entre la fin de la plage et la fin du conteneur (donc l'effacement d'un élément de la fin prend un temps constant) .
C++ 2003 [lib.vector.modifiers]
Se lit comme suit:
iterator erase(iterator position);
iterator erase(iterator first, iterator last);`
...
Complexité: Le destructeur de
T
est appelé le nombre de fois égal au nombre des éléments effacés, mais l'affectation L'opérateur deT
est appelé le nombre de fois égal au nombre d'éléments dans le vecteur après les éléments effacés.
C++ 14 draft N4140 [vector.modifiers]
Se lit comme suit:
Complexité: Le destructeur de
T
est appelé le nombre de fois égal au nombre d'éléments effacés, mais le mouvement L'opérateur d'affectation deT
est appelé le nombre de fois égal au nombre d'éléments dans le vecteur après les éléments effacés.
Vous voyez donc que l'implémentation C++ 11/14 est plus efficace en général car elle effectue une affectation de déplacement au lieu d'une affectation de copie, mais la complexité reste la même.
La complexité de std::deque::erase()
est linéaire à la fois à la longueur de la plage effacée et au minimum de deux nombres: nombre d'éléments restants avant le début de la plage et le nombre d'éléments restants après la fin de la plage. Ainsi, l'effacement d'un élément depuis le début ou la fin prend un temps constant.
C++ 2003 [lib.deque.modifiers]
:
iterator erase(iterator position);
iterator erase(iterator first, iterator last);
Complexité: Le nombre d'appels au destructeur est le même que le nombre d'éléments effacés, mais le nombre d'appels à l'opérateur d'affectation est à le plus égal au minimum du nombre d'éléments avant les éléments effacés et du nombre d'éléments après les éléments effacés.
C++ 14 draft N4140 [deque.modifiers]/5
:
Complexité: Le nombre d'appels au destructeur est le même que le nombre d'éléments effacés, mais le nombre d'appels à l'opérateur d'affectation n'est plus que le moindre du nombre d'éléments avant les éléments effacés et du nombre d'éléments après les éléments effacés.
Donc, c'est la même chose en C++ 98 et C++ 11/14, sauf que C++ 11 peut choisir entre l'affectation de déplacement et l'affectation de copie (ici, je vois une incohérence dans la norme car le libellé ne mentionne pas déplacer affectation comme pour std::vector
- pourrait être une raison pour une autre question).
Notez également "au plus" et "plus" dans les termes. Cela permet aux implémentations d'être plus efficaces que linéaires, bien qu'en pratique elles soient linéaires ( DÉMO ).
Supprimer des éléments n'est en effet O(n)
pas à cause de ce que vous devez faire pour trouver l'élément à supprimer mais à cause de ce que vous devez faire pour tous ceux après le. Ces éléments doivent être glissés pour remplir l'emplacement vide.
Donc, en moyenne, l'effacement prendra un élément à mi-chemin du vecteur, vous devrez donc déplacer environ la moitié des éléments. D'où O(n)
. Dans le meilleur des cas, vous effacez le dernier élément - aucun glissement nécessaire. Dans le pire des cas, vous effacez le premier élément - vous devez ensuite déplacer chaque autre élément.
L'effacement d'un élément dans un vecteur est O(n) car une fois que vous avez supprimé l'élément, vous devez toujours déplacer tous les éléments successifs pour combler le vide créé. Si un vecteur a n éléments, alors à la dans le pire des cas, vous devrez déplacer n-1 elemets, d'où la complexité est O (n).
en utilisant de cette façon la complexité temporelle = longueur de plage + longueur de décalage (n - fin de plage)
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it, it+length);