c#
.net
vb.net
data-structures
linked-list
Jonathan Allen
fuente
fuente
Respuestas:
Editar
Respuesta original ...
Encontré resultados interesantes:
Lista vinculada (3,9 segundos)
Lista (2,4 segundos)
¡Incluso si solo accedes a los datos esencialmente, es mucho más lento! Yo digo que nunca uses una lista enlazada.
Aquí hay otra comparación que realiza muchas inserciones (planeamos insertar un elemento en el medio de la lista)
Lista vinculada (51 segundos)
Lista (7,26 segundos)
Lista vinculada con referencia de ubicación donde insertar (.04 segundos)
Entonces, solo si planea insertar varios elementos y también en algún lugar tiene la referencia de dónde planea insertar el elemento, use una lista vinculada. El hecho de que tenga que insertar muchos elementos no lo hace más rápido, ya que la búsqueda de la ubicación en la que desea insertarlo lleva tiempo.
fuente
list.AddLast(a);
en los últimos dos ejemplos de LinkedList? Lo hago una vez antes del bucle, comolist.AddLast(new Temp(1,1,1,1));
en la penúltima LinkedList, pero (para mí) parece que estás agregando el doble de objetos Temp en los mismos bucles. (Y cuando vuelvo a verificar con una aplicación de prueba ,I say never use a linkedList.
es defectuoso como revela su publicación posterior. Es posible que desee editarlo. 2) ¿Qué estás cronometrando? ¿Instanciación, suma y enumeración en un solo paso? Principalmente, la creación de instancias y la enumeración no son lo que preocupa a las personas, son pasos únicos. Específicamente el tiempo de las inserciones y adiciones daría una mejor idea. 3) Lo más importante es que está agregando más de lo requerido a una lista vinculada. Esta es una comparación incorrecta. Difunde una idea equivocada sobre la lista vinculada.En la mayoría de los casos,
List<T>
es más útil.LinkedList<T>
tendrá menos costo al agregar / eliminar elementos en el medio de la lista, mientrasList<T>
que solo puede agregar / eliminar de forma económica al final de la lista.LinkedList<T>
solo es más eficiente si está accediendo a datos secuenciales (ya sea hacia adelante o hacia atrás): el acceso aleatorio es relativamente costoso, ya que debe recorrer la cadena cada vez (por lo tanto, no tiene un indexador). Sin embargo, dado que aList<T>
es esencialmente solo una matriz (con un contenedor), el acceso aleatorio está bien.List<T>
También ofrece una gran cantidad de métodos de apoyo -Find
,ToArray
, etc; sin embargo, estos también están disponibles paraLinkedList<T>
.NET 3.5 / C # 3.0 a través de métodos de extensión, por lo que eso es menos importante.fuente
List<T>
yT[]
fallará por ser demasiado grueso (una sola losa),LinkedList<T>
llorará por ser demasiado granular (losa por elemento).Pensar en una lista vinculada como una lista puede ser un poco engañoso. Es más como una cadena. De hecho, en .NET,
LinkedList<T>
ni siquiera se implementaIList<T>
. No existe un concepto real de índice en una lista vinculada, aunque parezca que sí. Ciertamente, ninguno de los métodos proporcionados en la clase acepta índices.Las listas vinculadas pueden estar individualmente vinculadas o doblemente vinculadas. Esto se refiere a si cada elemento de la cadena tiene un enlace solo con el siguiente (vinculado individualmente) o con los elementos anteriores / siguientes (doblemente vinculados).
LinkedList<T>
está doblemente vinculadoInternamente,
List<T>
está respaldado por una matriz. Esto proporciona una representación muy compacta en la memoria. Por el contrario,LinkedList<T>
implica memoria adicional para almacenar los enlaces bidireccionales entre elementos sucesivos. Por lo tanto, la huella de memoria de aLinkedList<T>
generalmente será mayor que paraList<T>
(con la advertencia de queList<T>
puede tener elementos de matriz internos no utilizados para mejorar el rendimiento durante las operaciones de adición).También tienen diferentes características de rendimiento:
Adjuntar
LinkedList<T>.AddLast(item)
tiempo constanteList<T>.Add(item)
tiempo constante amortizado, peor caso linealAnteponer
LinkedList<T>.AddFirst(item)
tiempo constanteList<T>.Insert(0, item)
tiempo linealInserción
LinkedList<T>.AddBefore(node, item)
tiempo constanteLinkedList<T>.AddAfter(node, item)
tiempo constanteList<T>.Insert(index, item)
tiempo linealEliminación
LinkedList<T>.Remove(item)
tiempo linealLinkedList<T>.Remove(node)
tiempo constanteList<T>.Remove(item)
tiempo linealList<T>.RemoveAt(index)
tiempo linealContar
LinkedList<T>.Count
tiempo constanteList<T>.Count
tiempo constanteContiene
LinkedList<T>.Contains(item)
tiempo linealList<T>.Contains(item)
tiempo linealClaro
LinkedList<T>.Clear()
tiempo linealList<T>.Clear()
tiempo linealComo puede ver, son en su mayoría equivalentes. En la práctica, la API de
LinkedList<T>
es más engorrosa de usar y los detalles de sus necesidades internas se derraman en su código.Sin embargo, si necesita hacer muchas inserciones / eliminaciones desde una lista, ofrece tiempo constante.
List<T>
ofrece tiempo lineal, ya que los elementos adicionales en la lista se deben barajar después de la inserción / eliminación.fuente
Las listas vinculadas proporcionan una inserción o eliminación muy rápida de un miembro de la lista. Cada miembro de una lista vinculada contiene un puntero al siguiente miembro de la lista para insertar un miembro en la posición i:
La desventaja de una lista vinculada es que el acceso aleatorio no es posible. Acceder a un miembro requiere recorrer la lista hasta que se encuentre el miembro deseado.
fuente
Mi respuesta anterior no fue lo suficientemente precisa. Como realmente fue horrible: D Pero ahora puedo publicar una respuesta mucho más útil y correcta.
Hice algunas pruebas adicionales. Puede encontrar su fuente en el siguiente enlace y volver a verificarlo en su entorno: https://github.com/ukushu/DataStructuresTestsAndOther.git
Resultados cortos:
Matriz necesita usar:
Lista necesita usar:
LinkedList necesita usar:
Más detalles:
Interesante saber:
LinkedList<T>
internamente no es una Lista en .NET. Incluso no se implementaIList<T>
. Y es por eso que hay índices y métodos ausentes relacionados con los índices.LinkedList<T>
es una colección basada en puntero de nodo. En .NET está en implementación doblemente vinculada. Esto significa que los elementos anteriores / siguientes tienen un enlace al elemento actual. Y los datos están fragmentados: se pueden ubicar diferentes objetos de lista en diferentes lugares de RAM. También habrá más memoria utilizada paraLinkedList<T>
que paraList<T>
o Array.List<T>
en .Net es la alternativa de Java deArrayList<T>
. Esto significa que este es un contenedor de matriz. Por lo tanto, se asigna en la memoria como un bloque contiguo de datos. Si el tamaño de datos asignado supera los 85000 bytes, se moverá a Montón de objetos grandes. Dependiendo del tamaño, esto puede conducir a la fragmentación del montón (una forma leve de pérdida de memoria). Pero al mismo tiempo si el tamaño es <85000 bytes, esto proporciona una representación muy compacta y de acceso rápido en la memoria.Se prefiere un bloque contiguo único para el rendimiento de acceso aleatorio y el consumo de memoria, pero para las colecciones que necesitan cambiar regularmente el tamaño, una estructura como una matriz generalmente debe copiarse en una nueva ubicación, mientras que una lista vinculada solo necesita administrar la memoria para el recién insertado / nodos eliminados.
fuente
La diferencia entre List y LinkedList radica en su implementación subyacente. La lista es una colección basada en matriz (ArrayList). LinkedList es una colección basada en puntero de nodo (LinkedListNode). En el uso de nivel API, ambos son prácticamente iguales ya que ambos implementan el mismo conjunto de interfaces como ICollection, IEnumerable, etc.
La diferencia clave viene cuando el rendimiento es importante. Por ejemplo, si está implementando la lista que tiene una operación pesada "INSERTAR", LinkedList supera a List. Dado que LinkedList puede hacerlo en tiempo O (1), pero List puede necesitar expandir el tamaño de la matriz subyacente. Para obtener más información / detalles, es posible que desee leer sobre la diferencia algorítmica entre LinkedList y las estructuras de datos de matriz. http://en.wikipedia.org/wiki/Linked_list and Array
Espero que esto ayude,
fuente
Add
que siempre está al final de la matriz existente.List
es "suficientemente bueno" en eso, incluso si no es O (1). El problema grave se produce si necesita muchosAdd
correos electrónicos que no están al final. Marc señala que la necesidad de mover datos existentes cada vez que inserte (no solo cuando se necesita cambiar el tamaño) es un costo de rendimiento más sustancialList
.La principal ventaja de las listas vinculadas sobre las matrices es que los enlaces nos brindan la capacidad de reorganizar los elementos de manera eficiente. Sedgewick, pág. 91 91
fuente
Una circunstancia común para usar LinkedList es así:
Suponga que desea eliminar muchas cadenas determinadas de una lista de cadenas con un tamaño grande, digamos 100,000. Las cadenas para eliminar se pueden buscar en HashSet dic, y se cree que la lista de cadenas contiene entre 30,000 y 60,000 cadenas para eliminar.
Entonces, ¿cuál es el mejor tipo de lista para almacenar las 100.000 cadenas? La respuesta es LinkedList. Si se almacenan en una ArrayList, la iteración sobre ella y la eliminación de cadenas coincidentes requeriría miles de millones de operaciones, mientras que solo se necesitan alrededor de 100,000 operaciones mediante el uso de un iterador y el método remove ().
fuente
RemoveAll
para eliminar los elementos de aList
sin mover muchos elementos, o usarWhere
de LINQ para crear una segunda lista.LinkedList
Sin embargo, el uso de un aquí termina consumiendo dramáticamente más memoria que otros tipos de colecciones y la pérdida de la localidad de memoria significa que será notablemente más lento para iterar, lo que lo hace un poco peor que aList
.RemoveAll
equivalente en Java.RemoveAll
no está disponible paraList
, podría hacer un algoritmo de "compactación", que se vería como el bucle de Tom, pero con dos índices y la necesidad de mover elementos para mantenerse uno a la vez en la matriz interna de la lista. La eficiencia es O (n), lo mismo que para el algoritmo de TomLinkedList
. En ambas versiones, domina el tiempo para calcular la clave HashSet para las cadenas. Este no es un buen ejemplo de cuándo usarloLinkedList
.Cuando necesite acceso indexado incorporado, clasificación (y después de esta búsqueda binaria) y método "ToArray ()", debe usar List.
fuente
Esencialmente, un
List<>
en .NET es un contenedor sobre una matriz . ALinkedList<>
es una lista vinculada . Entonces, la pregunta se reduce a cuál es la diferencia entre una matriz y una lista vinculada, y cuándo debe usarse una matriz en lugar de una lista vinculada. Probablemente los dos factores más importantes en su decisión de cuál usar se reducirían a:fuente
Esto está adaptado de la respuesta aceptada de Tono Nam corrigiendo algunas mediciones incorrectas.
La prueba:
Y el codigo:
Puede ver que los resultados están de acuerdo con el rendimiento teórico que otros han documentado aquí. Muy claro:
LinkedList<T>
gana mucho tiempo en caso de inserciones. No he probado la eliminación del medio de la lista, pero el resultado debería ser el mismo. Por supuesto,List<T>
tiene otras áreas donde funciona mucho mejor como el acceso aleatorio O (1).fuente
Usar
LinkedList<>
cuandoToken Stream
.Para todo lo demás, es mejor usarlo
List<>
.fuente
LinkedListNode<T>
objetos en su código. Si puede hacer eso, entonces es mucho mejor que usarList<T>
, especialmente para listas muy largas donde las inserciones / extracciones son frecuentes.node.Value
cuando quiere el elemento original). Entonces reescribe el algoritmo para trabajar con nodos, no con valores sin formato.Estoy de acuerdo con la mayoría de los puntos mencionados anteriormente. Y también estoy de acuerdo en que List parece una opción más obvia en la mayoría de los casos.
Pero, solo quiero agregar que hay muchas instancias en las que LinkedList es una opción mucho mejor que List para una mejor eficiencia.
Espero que alguien encuentre útiles estos comentarios.
fuente
Tantas respuestas promedio aquí ...
Algunas implementaciones de listas vinculadas utilizan bloques subyacentes de nodos preasignados. Si no lo hacen, el tiempo constante / tiempo lineal es menos relevante ya que el rendimiento de la memoria será deficiente y el rendimiento de la memoria caché será aún peor.
Use listas vinculadas cuando
1) Desea seguridad del hilo. Puedes construir mejores algos seguros para hilos. Los costos de bloqueo dominarán una lista de estilos concurrentes.
2) Si tiene una cola grande como estructuras y desea eliminar o agregar en cualquier lugar excepto el final todo el tiempo. > Existen 100K listas pero no son tan comunes.
fuente
Hice una pregunta similar relacionada con el rendimiento de la colección LinkedList , y descubrí que el implemento C # de Deque de Steven Cleary era una solución. A diferencia de la colección Queue, Deque permite mover elementos hacia adelante y hacia atrás. Es similar a la lista vinculada, pero con un rendimiento mejorado.
fuente
Deque
es "similar a la lista vinculada, pero con un rendimiento mejorado" . Por favor calificar esa declaración:Deque
es un mejor rendimiento queLinkedList
, para su código específico . Siguiendo su enlace, veo que dos días después usted aprendió de Ivan Stoev que esto no era una ineficiencia de LinkedList, sino una ineficiencia en su código. (E incluso si hubiera sido una ineficiencia de LinkedList, eso no justificaría una declaración general de que Deque es más eficiente; solo en casos específicos.)