web-dev-qa-db-fra.com

Un moyen rapide d'implémenter pop_front dans un std :: vector

J'utilise certaines classes et plusieurs méthodes utilitaires qui utilisent std :: vector.

Maintenant, je dois utiliser chaque image d'une méthode pop_front - Push_back sur l'une de ces classes (mais elles sont toutes liées et fonctionnent ensemble, donc je ne peux pas en changer une seule).

La plupart des opérations sont itérées sur toutes les opérations d'élément et de Push_back, donc ce que je dois faire pour le meilleur travail est: fork le référentiel de ces classes et utilitaires, modèle tout, et utilisez deque ou list.

Mais cela signifie beaucoup de réécriture de code et beaucoup de tests qui me feront manquer la date limite.

J'ai donc besoin de conseils pour écrire un pop_front efficace dans un vecteur de taille statique (la taille ne changera pas).

J'ai trouvé ici un moyen:

template<typename T>
void pop_front(std::vector<T>& vec)
{
   vec.front() = vec.back();
   vec.pop_back();
   vec.front() = vec.back();  // but should this work?
}

Et une autre idée devrait être:

template<typename T>
void pop_front(std::vector<T>& vec, already_allocated_vector vec1)
{
   vec1.clear();
   copy(vec.begin(), vec.end()-1, vec1.begin());
   copy(vec1.begin(), vec1.end(), vec.begin());
}

Quelle est la plus rapide de ces deux solutions? D'autres solutions?

20
nkint

Je m'attendrais à:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.front() = std::move(vec.back());
    vec.pop_back();
}

pour être le moyen le plus efficace de le faire, mais il ne maintient pas l'ordre des éléments dans le vecteur.

Si vous devez conserver l'ordre des éléments restants dans vec, vous pouvez faire:

template<typename T>
void pop_front(std::vector<T>& vec)
{
    assert(!vec.empty());
    vec.erase(vec.begin());
}

Cela aura un temps linéaire dans le nombre d'éléments dans vec, mais c'est le mieux que vous puissiez faire sans changer votre structure de données.

Aucune de ces fonctions ne maintiendra le vector à une taille constante, car un pop_front l'opération va par définition supprimer un élément d'un conteneur.

29
Mankarse

Puisque pop_front() n'efface que le premier élément, l'implémentation directe est la suivante:

template <typename V>
void pop_front(V & v)
{
    assert(!v.empty());
    v.erase(v.begin());
}

Ne vous inquiétez pas de la vitesse pour l'instant. Si vous souhaitez revenir en arrière et optimiser le code, demandez du temps dédié au projet.

6
Kerrek SB

si vous essayez simplement d'effacer le premier élément, utilisez la fonction:

if (my_vector.size()){ //check if there any elements in the vector array
    my_vector.erase(my_vector.begin()); //erase the firs element
}

si vous voulez émuler le front de pop pour l'ensemble du tableau de vecteurs (vous voulez garder pop chaque élément du début à la fin), je suggère:

reverse(my_vector.begin(),my_vector.end());  // reverse the order of the vector array
my_vector.pop_back();   // now just simple pop_back will give you the results
1
0xPwn

J'ai aussi un moyen ... Pas si bon que ça ..

Cela ressemble à la solution de @ 0xPwn, mais il n'a pas inversé le vecteur la deuxième fois. Vous comprendrez probablement ce code, donc je ne l'expliquerai pas.

#include <algorithm>
#include <vector>
template <typename T>
void pop_front(std::vector<T>& vec){
    std::reverse(vec.begin(),vec.end()); // first becomes last, reverses the vector
    vec.pop_back(); // pop last
    std::reverse(vec.begin(),vec.end()); // reverses it again, so the elements are in the same order as before

}
1
CppPythonDude