2012-02-25 17 views
13

Estoy usando algunas clases y varios métodos de utilidad que usan std :: vector.manera rápida de implementar pop_front a std :: vector

Ahora necesito usar cada fotograma un método pop_front - push_back en una de esas clases (pero todas están vinculadas, y funcionan juntas, así que no puedo cambiar solo una).

La mayoría de las operaciones se repiten sobre todas las operaciones de elementos y push_back, entonces lo que debo hacer para el mejor trabajo es: bifurcar el repositorio de esas clases y utilidades, plantilla todo y usar deque o list.

Pero esto significa mucha reescritura de código y muchas pruebas que me harán perder la fecha límite.

Así que necesito consejos para escribir un pop_front eficiente en un vector de tamaño estático (el tamaño no cambiará).

he encontrado una manera here:

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? 
} 

Y otra idea debería ser:

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()); 
} 

¿Cuál es el más rápido de estas dos soluciones? ¿Alguna otra solución?

+0

¿Qué quiere decir con "el tamaño no cambiará"? Después de hacer pop_front, ¿el vector tendrá el mismo tamaño que antes? Si es así, ¿el último elemento debería ser basura? –

+0

el vector tiene el mismo tamaño, porque después de un pop de repente hago un push. cada foto hice un pop y un push en el mismo método, así que antes y después de este método, el vector es del mismo tamaño – nkint

+4

Antes de preocuparse por la velocidad, preocúpese por ** corrección **. Toda la velocidad en el mundo no significa nada si el resultado que obtienes es simplemente incorrecto, y por lo que yo sé, tus dos candidatos están equivocados. El primero debe llamarse 'pop_back_and_overwrite_front_with_penultimate', y el segundo debe llamarse' invoke_undefined_behavior_and_pop_back'. (Escribir en 'vec1.begin()' no está definido porque 'vec1' está vacío; sería necesario escribir' vec1.resize (vec.size() - 1) 'en lugar de' vec1.clear() '.) Cuando trato con operaciones vectoriales, a veces dibujo una imagen. Quizás eso también te ayude. –

Respuesta

21

yo esperaría:

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

a ser la forma más eficiente de hacerlo, pero no mantiene el orden de los elementos en el vector.

Si necesita mantener el orden de los elementos restantes en vec, que puede hacer:

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

Esto tendrá tiempo lineal en el número de elementos en vec, pero es lo mejor que puede hacer sin cambiar su estructura de datos

Ninguna de estas funciones mantengan la vector en un tamaño constante, porque una operación de pop_front se por definición eliminar un elemento de un contenedor.

+0

Necesito el orden .. – nkint

+0

Creo que se supone que el orden debe conservarse ya que' std :: vector :: pop_back' conserva el orden . – HelloGoodbye

+0

no es mejor incluir 'vec.push_back (new_value) vec.shrink_to_fit()' después? –

5

Desde pop_front() sólo borra el primer elemento, la aplicación directa es la siguiente:

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

No se preocupe por la velocidad por ahora. Si desea volver atrás y optimizar el código, solicite tiempo dedicado al proyecto.

+2

Esto se parece más a una función 'pop_everything_but_front' ... – Mankarse

+0

lo siento, no entiendo su código, ¿no debería guardar solo el primer elemento? Quiero borrar solo el primer elemento, no debería ser: v.erase (v.begin(), v.begin() + 1); ? – nkint

+0

@Mankarse: Sí, ¡oh! ¡Gracias! –

3

IgushArray (https://github.com/igushev/IgushArray) que, como una matriz, tiene una operación rápida de acceso constante, pero la operación de inserción/borrado toma solo O (N^1/2) tiempo. Entonces, en su caso, insertarlo al comienzo sería muy efectivo aquí. Tenga cuidado, la estructura es muy sensible para la reserva().

template <class T> 
void pop_front(IgushArray<T>& v) 
{ 
    if (!v.empty()) 
    v.erase(v.begin()); 
} 

En la primera opción que escribió usted viola el orden de los elementos. ¿Es un problema?

Si es así, utilice la variante que escribí.

Si no es así y el orden de los elementos no importa en absoluto, puede ser mejor usar std :: set o std :: multiset.

1

si sólo intenta borrar el primer elemento a continuación, en la función de su uso:

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

si desea emular frontal pop por toda la matriz de vectores (que desea mantener el pop a cabo todos los elementos desde el principio hasta fin), sugiero en:

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 
Cuestiones relacionadas