Noté en Effective STL que
vector es el tipo de secuencia que debe usarse por defecto.
¿Qué significa? Parece que ignorar la eficiencia vector
puede hacer cualquier cosa.
¿Alguien podría ofrecerme un escenario en el vector
que no sea una opción factible pero list
deba usarse?
Respuestas:
Situaciones en las que desea insertar una gran cantidad de elementos en cualquier lugar que no sea el final de una secuencia repetidamente.
Consulte las garantías de complejidad para cada tipo diferente de contenedor:
¿Cuáles son las garantías de complejidad de los contenedores estándar?
fuente
list
tienepush_front
vector:
lista:
En general, use el vector cuando no le importa qué tipo de contenedor secuencial está utilizando, pero si está haciendo muchas inserciones o borrados hacia y desde cualquier parte del contenedor que no sea el final, querrá para usar la lista. O si necesita acceso aleatorio, entonces querrá un vector, no una lista. Aparte de eso, naturalmente hay casos en los que necesitará uno u otro según su aplicación, pero en general, esas son buenas pautas.
fuente
reserve()
para reducir eso a O (1). Agregar nuevos elementos a una lista (es decir, no empalmarlos) realiza O (n) asignaciones de tiendas gratuitas.list
libera memoria cuando borra elementos, perovector
no lo hace. Avector
no reduce su capacidad cuando reduce su tamaño, a menos que use elswap()
truco.Si no necesita insertar elementos con frecuencia, un vector será más eficiente. Tiene una localidad de caché de CPU mucho mejor que una lista. En otras palabras, acceder a un elemento hace muy probable que el siguiente elemento esté presente en la memoria caché y pueda recuperarse sin tener que leer RAM lenta.
fuente
La mayoría de las respuestas aquí pierden un detalle importante: ¿para qué?
¿Qué quieres mantener en el contactor?
Si se trata de una colección de
int
s, entoncesstd::list
perderá en todos los escenarios, sin tener en cuenta si se puede reasignar, sólo se quita desde el frente, etc. Las listas son más lentas a través, cada inserción le cuesta una interacción con el asignador. Sería extremadamente difícil preparar un ejemplo, dondelist<int>
latevector<int>
. E incluso entonces,deque<int>
puede ser mejor o cercano, no justificando el uso de listas, que tendrán una mayor sobrecarga de memoria.Sin embargo, si se trata de grandes y feos bloques de datos, y pocos de ellos, no desea sobreasignarlos al insertarlos y copiarlos debido a la reasignación sería un desastre; entonces, tal vez, sea mejor que tenga
list<UglyBlob>
quevector<UglyBlob>
.Aún así, si cambia
vector<UglyBlob*>
ao inclusovector<shared_ptr<UglyBlob> >
, nuevamente, la lista se retrasará.Entonces, el patrón de acceso, el recuento de elementos objetivo, etc., todavía afecta la comparación, pero en mi opinión, el tamaño de los elementos, el costo de la copia, etc.
fuente
list<T>
la posibilidad desplice
en O (1) . Si necesita un empalme de tiempo constante, la lista también puede ser la estructura elegida;)UglyBlob
- incluso un objeto con sólo unos pocos miembros de cuerda pueden ser fácilmente prohibitivamente caro para copiar, por lo que las reasignaciones serán costar. Además: no descuide el espacio superior quevector
puede causar el crecimiento exponencial de un objeto de retención de unas pocas docenas de bytes de tamaño (si no puede hacerloreserve
de antemano).vector<smart_ptr<Large>>
vs.list<Large>
, diría que si necesita acceso aleatorio a los elementos,vector
tiene sentido. Si no necesita acceso aleatorio,list
parece más simple y debería funcionar por igual.Una capacidad especial de std :: list es el empalme (vincular o mover parte o una lista completa a una lista diferente).
O tal vez si sus contenidos son muy caros de copiar. En tal caso, podría ser más barato, por ejemplo, ordenar la colección con una lista.
También tenga en cuenta que si la colección es pequeña (y el contenido no es particularmente costoso de copiar), un vector aún podría superar a una lista, incluso si inserta y borra en cualquier lugar. Una lista asigna cada nodo individualmente, y eso podría ser mucho más costoso que mover algunos objetos simples.
No creo que haya reglas muy estrictas. Depende de lo que desee hacer principalmente con el contenedor, así como de qué tan grande espere que sea el contenedor y el tipo contenido. Un vector generalmente triunfa sobre una lista, porque asigna su contenido como un solo bloque contiguo (es básicamente una matriz asignada dinámicamente, y en la mayoría de las circunstancias, una matriz es la forma más eficiente de contener un montón de cosas).
fuente
list::size
no es necesariamente tiempo constante. Ver stackoverflow.com/questions/228908/is-listsize-really-on y gcc.gnu.org/ml/libstdc++/2005-11/msg00219.htmlsplice
entre diferentes listas se especifica como complejidad lineal ysize
es específicamente constante. Por lo tanto, para acomodar a los principiantes que iteransize
o lo que sea, una clase completa de algoritmos está fuera del alcance de la STL o cualquier período de contenedores "conformes".Bueno, los estudiantes de mi clase parecen incapaces de explicarme cuándo es más efectivo usar vectores, pero se ven muy felices cuando me aconsejan que use listas.
Así es como lo entiendo
Liza : cada elemento contiene una dirección para el elemento siguiente o anterior, por lo que con esta función, puede aleatorizar los elementos, incluso si no están ordenados, el orden no cambiará: es eficiente si su memoria está fragmentada. Pero también tiene otra gran ventaja: puede insertar / eliminar elementos fácilmente, porque lo único que debe hacer es cambiar algunos punteros. Inconveniente: para leer un elemento individual aleatorio, debe saltar de un elemento a otro hasta encontrar la dirección correcta.
Vectores : cuando se usan vectores, la memoria está mucho más organizada como las matrices regulares: cada elemento n se almacena justo después del elemento (n-1) y antes del elemento (n + 1). ¿Por qué es mejor que la lista? Porque permite un acceso aleatorio rápido. Aquí se explica cómo: si conoce el tamaño de un elemento en un vector y si están contiguos en la memoria, puede predecir fácilmente dónde está el enésimo elemento; no tiene que examinar todo el elemento de una lista para leer el que desea, con vector, lo lee directamente, con una lista que no puede. Por otro lado, modificar la matriz de vectores o cambiar un valor es mucho más lento.
Las listas son más apropiadas para realizar un seguimiento de los objetos que se pueden agregar / eliminar en la memoria. Los vectores son más apropiados cuando desea acceder a un elemento desde una gran cantidad de elementos individuales.
No sé cómo se optimizan las listas, pero debe saber que si desea un acceso de lectura rápido, debe usar vectores, porque cuán bueno es el STL para sujetar las listas, no será tan rápido en el acceso de lectura como el vector.
fuente
vector
causado por cambiar su tamaño puede ser lento? luego acordó, pero en los casos en quereserve()
se puede utilizar, eso evita esos problemas.Básicamente, un vector es una matriz con gestión automática de memoria. Los datos son contiguos en la memoria. Intentar insertar datos en el medio es una operación costosa.
En una lista, los datos se almacenan en ubicaciones de memoria no relacionadas. Insertar en el medio no implica copiar algunos de los datos para dejar espacio para el nuevo.
Para responder más específicamente a su pregunta, citaré esta página
fuente
En cualquier momento no se pueden invalidar los iteradores.
fuente
deque
.Cuando tienes mucha inserción o eliminación en el medio de la secuencia. Por ejemplo, un administrador de memoria.
fuente
Preservar la validez de los iteradores es una razón para usar una lista. Otra es cuando no desea que un vector se reasigne al insertar elementos. Esto se puede gestionar mediante un uso inteligente de reserve (), pero en algunos casos puede ser más fácil o más factible usar una lista.
fuente
Cuando desee mover objetos entre contenedores, puede usarlos
list::splice
.Por ejemplo, un algoritmo de partición de gráficos puede tener un número constante de objetos divididos recursivamente entre un número creciente de contenedores. Los objetos deben inicializarse una vez y permanecer siempre en las mismas ubicaciones en la memoria. Es mucho más rápido reorganizarlos volviendo a vincular que reasignando.
Editar: a medida que las bibliotecas se preparan para implementar C ++ 0x, el caso general de empalmar una subsecuencia en una lista se está convirtiendo en una complejidad lineal con la longitud de la secuencia. Esto se debe a que
splice
(ahora) necesita iterar sobre la secuencia para contar la cantidad de elementos que contiene. (Debido a que la lista necesita registrar su tamaño). Simplemente contar y volver a vincular la lista es aún más rápido que cualquier alternativa, y empalmar una lista completa o un solo elemento son casos especiales con complejidad constante. Pero, si tiene secuencias largas para empalmar, es posible que tenga que buscar un contenedor mejor, anticuado y no compatible.fuente
La única regla estricta donde
list
debe usarse es donde necesita distribuir punteros a elementos del contenedor.A diferencia de
vector
, usted sabe que la memoria de los elementos no se reasignará. Si pudiera ser así, podría tener punteros a la memoria no utilizada, que es, en el mejor de los casos, un gran no-no y, en el peor de los casos, aSEGFAULT
.(Técnicamente, una
vector
de*_ptr
también funcionaría, pero en ese caso estás emulando,list
así que eso es solo semántica).Otras reglas suaves tienen que ver con los posibles problemas de rendimiento de insertar elementos en el medio de un contenedor, por lo
list
que sería preferible.fuente
Hágalo simple:
al final del día, cuando esté confundido al elegir contenedores en C ++, use esta imagen de diagrama de flujo (Dígame gracias): ingrese la descripción de la imagen aquí
Vector-
1. el vector se basa en la memoria contagiosa
2. el vector es el camino a seguir para un conjunto de datos pequeño
3. el vector funciona más rápido mientras se recorre en el conjunto de datos
4. la eliminación de inserción del vector es lenta en un conjunto de datos enorme pero rápido para muy pequeños
Lista-
1. la lista se basa en la memoria de almacenamiento dinámico
2. la lista es el camino a seguir para un conjunto de datos muy grande
3. la lista es relativamente lenta al atravesar un conjunto de datos pequeño pero rápido en un conjunto de datos enorme
4. la eliminación de la inserción de la lista es rápida gran conjunto de datos pero lento en los más pequeños
fuente
Las listas son solo un contenedor para una lista doblemente enlazada en stl, por lo que ofrecen una característica que puede esperar de d-linklist, a saber, inserción y eliminación de O (1). Mientras que los vectores son una secuencia de datos contagiosa que funciona como una matriz dinámica. PS: más fácil de atravesar.
fuente
En el caso de un vector y una lista , las principales diferencias que me destacan son las siguientes:
vector
Un vector almacena sus elementos en la memoria contigua. Por lo tanto, el acceso aleatorio es posible dentro de un vector, lo que significa que acceder a un elemento de un vector es muy rápido porque simplemente podemos multiplicar la dirección base con el índice del elemento para acceder a ese elemento. De hecho, solo se necesita O (1) o tiempo constante para este propósito.
Dado que un vector básicamente envuelve una matriz, cada vez que inserta un elemento en el vector (matriz dinámica), tiene que cambiar su tamaño encontrando un nuevo bloque contiguo de memoria para acomodar los nuevos elementos que es costoso en tiempo.
No consume memoria adicional para almacenar punteros a otros elementos dentro de él.
lista
Una lista almacena sus elementos en memoria no contigua. Por lo tanto, el acceso aleatorio no es posible dentro de una lista, lo que significa que para acceder a sus elementos tenemos que usar los punteros y recorrer la lista que es más lenta en relación con el vector. Esto toma O (n) o tiempo lineal que es más lento que O (1).
Como una lista usa memoria no contigua, el tiempo necesario para insertar un elemento dentro de una lista es mucho más eficiente que en el caso de su contraparte vectorial porque se evita la reasignación de memoria.
Consume memoria extra para almacenar punteros al elemento antes y después de un elemento en particular.
Por lo tanto, teniendo en cuenta estas diferencias, generalmente consideramos la memoria , el acceso aleatorio frecuente y la inserción para decidir el ganador del vector frente a la lista en un escenario dado.
fuente
La lista es una lista doblemente vinculada, por lo que es fácil insertar y eliminar un elemento. Solo tenemos que cambiar los pocos punteros, mientras que en el vector si queremos insertar un elemento en el medio, cada elemento después de que tenga que cambiar un índice. Además, si el tamaño del vector está lleno, primero debe aumentar su tamaño. Por lo tanto, es una operación costosa. Por lo tanto, siempre que se requiera que las operaciones de inserción y eliminación se realicen con más frecuencia en dicha lista de casos, se debe utilizar.
fuente