¿Cuándo se debe utilizar LinkedList sobre las matrices?

Las listas vinculadas son preferibles a las matrices cuando:

a) necesita inserciones / eliminaciones en tiempo constante de la lista (como en la computación en tiempo real donde la previsibilidad del tiempo es absolutamente crítica)

b) no sabe cuántos elementos habrá en la lista. Con las matrices, es posible que deba volver a declarar y copiar memoria si la matriz crece demasiado

c) no necesita acceso aleatorio a ningún elemento

d) desea poder insertar elementos en el medio de la lista (como una cola de prioridad)

Las matrices son preferibles cuando:

a) necesita acceso indexado / aleatorio a los elementos

b) conoce el número de elementos en la matriz con anticipación para que pueda asignar la cantidad correcta de memoria para la matriz

c) necesita velocidad cuando recorre todos los elementos en secuencia. Puede usar las matemáticas del puntero en la matriz para acceder a cada elemento, mientras que debe buscar el nodo en función del puntero para cada elemento en la lista vinculada, lo que puede provocar fallas en la página que pueden dar lugar a resultados de rendimiento.

d) la memoria es una preocupación. Las matrices llenas ocupan menos memoria que las listas vinculadas. Cada elemento de la matriz es solo los datos. Cada nodo de la lista vinculada requiere los datos, así como uno (o más) punteros a los otros elementos en la lista vinculada.

Las listas de matrices (como las de .Net) le brindan los beneficios de las matrices, pero asignan recursos dinámicamente para que no tenga que preocuparse demasiado por el tamaño de la lista y pueda eliminar elementos en cualquier índice sin ningún esfuerzo o recuperación. barajando elementos alrededor. En cuanto al rendimiento, las listas de matrices son más lentas que las matrices sin procesar.

Una de las decisiones de diseño de aplicaciones más importantes involucra qué estructura de datos usar. Las matrices y las listas vinculadas se encuentran entre las estructuras de datos más comunes, y cada una es aplicable en diferentes situaciones.

Las matrices y las listas vinculadas están diseñadas para almacenar múltiples elementos, la mayoría de las veces del mismo tipo. Según la Computer Desktop Encyclopedia , una matriz es una disposición ordenada de elementos de datos a los que se accede mediante sus índices de referencia. Una lista vinculada es un grupo de elementos, cada uno de los cuales contiene un puntero que apunta al siguiente elemento.

Este artículo explorará las características de cada estructura para ayudarlo a determinar cuál es el mejor para su aplicación.

Dimensionamiento
Las matrices pueden ser unidimensionales o multidimensionales, según sus requisitos. Por ejemplo, podría usar una matriz unidimensional para almacenar los puntajes de todos los estudiantes en una clase para una prueba. Una matriz multidimensional sería mejor para almacenar los puntajes de todos los estudiantes para todas las pruebas durante el semestre. La Figura A proporciona un ejemplo de una matriz unidimensional, y la Figura B muestra una matriz multidimensional.

Figura A

Matriz unidimensional

Figura B

Matriz multidimensional

En la Figura B, los puntajes pueden promediarse por prueba (cruzada), por estudiante (abajo) o por clase (conjunto completo), mientras se mantiene cada puntaje único.

A diferencia de las matrices, las listas vinculadas son, por su propia naturaleza, unidimensionales. Pueden ser listas individualmente vinculadas, como se muestra en la Figura C , donde el recorrido de la lista se puede hacer en una sola dirección, o listas doblemente vinculadas, como en la Figura D , donde cada elemento apunta tanto al elemento anterior como al siguiente. en la lista.

Figura C

Lista vinculada individualmente

Figura D

Lista doblemente vinculada

Asignación de memoria
Muy a menudo, las matrices son estáticas, con su tamaño definido en la creación. Además, la memoria asignada para las matrices es contigua. Por lo tanto, se usan típicamente cuando se conoce el número máximo de elementos en tiempo de diseño. El inconveniente de este enfoque es que las matrices grandes requieren grandes cantidades de memoria, que pueden no utilizarse, especialmente aquellas diseñadas para un número máximo de elementos que a menudo no se acercarán a su capacidad. Y en algunas plataformas, como ciertos dispositivos portátiles que usan sistemas operativos más antiguos, las restricciones de memoria podrían limitar el tamaño de los arreglos que puede usar.

Por otro lado, las listas vinculadas suelen ser dinámicas. Pueden crecer y encogerse según sea necesario en tiempo de ejecución. Debido a este rasgo, las listas vinculadas son más atractivas cuando se desconoce el número de elementos. Además, la memoria de la lista vinculada se asigna elemento por elemento y, por lo tanto, rara vez es contigua. La desventaja de poder lidiar con la incertidumbre es que agregar y eliminar elementos a listas vinculadas requiere más sobrecarga que simplemente asignar valores a elementos de matriz preasignados. Pero los únicos límites sobre la cantidad de memoria que se puede asignar a una lista vinculada están impuestos por el tamaño del montón de memoria utilizado por la aplicación.

Acceso a elementos
Se accede a los elementos dentro de las matrices por sus índices. Por lo tanto, el acceso a los datos es fácil y rápido si sabe qué elemento recuperar. Si no conoce el índice del elemento necesario, pero los elementos se ordenan según un valor clave, puede realizar algoritmos de búsqueda altamente eficientes para localizar elementos específicos. Estos algoritmos permiten solo un número mínimo de comparaciones para ubicar un elemento único. También hay varios algoritmos establecidos y eficientes para ordenar y fusionar matrices. Sin embargo, las matrices son ineficientes cuando es probable que cambie el orden de sus elementos. Mantener una matriz ordenada tras la eliminación o inserción de elementos podría requerir la transferencia de cada elemento de la matriz.

Las listas vinculadas generalmente se recorren elemento por elemento hasta que se encuentre una coincidencia. Debido a que no se garantiza que la memoria para las listas vinculadas sea contigua, este recorrido de la lista es el único método para buscar en la lista (sin involucrar el uso de otras estructuras de datos como índices). La ventaja de la memoria no contigua es que reordenar la lista simplemente implica manipular los enlaces. La inserción o eliminación de un elemento requiere solo un par de modificaciones de puntero. La transferencia de los datos reales no es necesaria en absoluto.

Rompiendo las reglas
El uso de construcciones específicas del lenguaje puede permitir lo mejor de ambos mundos. Con C, los punteros a variables u objetos se pueden usar como matrices del tipo correspondiente si apuntan al primer elemento de una matriz asignada. Esto permite utilizar un puntero como matriz, pero cuando es necesario cambiar el tamaño, la función realloc () asigna un nuevo bloque de memoria y transfiere todos los elementos existentes a la nueva ubicación. Esta técnica permite cambiar el tamaño dinámico de una matriz mientras se mantiene la memoria contigua y la indexación de elementos.

Con Java, la clase de lista enlazada proporcionada ofrece una lista enlazada indexada que admite todos los métodos de lista estándar (superior, siguiente, anterior, etc.), así como la operación indexada. Los métodos indexOf () , get () y set () permiten el acceso de tipo matriz a los elementos de la lista. Además, Java proporciona una clase ArrayList que representa una implementación de matriz de tamaño variable de la clase de lista. Ambas clases admiten métodos para devolver matrices verdaderas de sus representaciones de lista.

Los lenguajes de programación continúan siendo más avanzados, y hay menos distinción entre los diversos tipos de implementaciones de datos a medida que sus estructuras se expanden para incluir las fortalezas y corregir las deficiencias encontradas en los modelos estándar. Sin embargo, siempre será importante recordar dónde se originaron estas estructuras y cómo todavía se usan dentro de las clases más nuevas. Aunque estas implementaciones más nuevas ocultan los detalles del programador, la sobrecarga computacional y los recursos necesarios no cambian.

Tomar la decisión
Si sus datos se representan mejor utilizando una estructura multidimensional, o si se conoce de antemano el número de elementos y seguirá siendo coherente, lo mejor es una matriz. Si sus datos se representan fácilmente en una dimensión, y se desconoce el número de elementos o se espera que cambie a menudo a lo largo de la operación de su programa, una lista vinculada es más eficiente.

Si se buscarán y accederán a sus datos con frecuencia, pero cambiarán con poca frecuencia, la matriz ofrece la menor sobrecarga para sus operaciones esperadas. Si espera agregar o restar elementos regularmente, especialmente si necesita mantener un orden ordenado, la versatilidad de la lista vinculada será de mayor beneficio

Gran pregunta! Me he enfrentado a algunos errores de corrupción de memoria muy perversos en mi vida profesional debido a este malentendido exacto de cuándo usar listas vinculadas.

Una matriz es una porción contigua de memoria. Cuando tu lo hagas

int * array = (int *) malloc (10 * sizeof (int));

Obtiene la dirección de un bloque de 10 enteros asignados uno al lado del otro para su uso.

Esto tiene varios beneficios. Uno es la velocidad. Puede subir y bajar este bloque simplemente con la aritmética del puntero.

* array es el primer elemento
* (array + 1) es el segundo
* (array + 2) es el tercer ..etc
O, de manera equivalente, utilizando una sintaxis de nivel superior:
matriz [0]
matriz [1]
matriz [2]

Por lo tanto, la matriz se indexa naturalmente por su desplazamiento en virtud de su diseño geométrico en la memoria. Esto no es un montón de humo y espejos y puntero indirecto. Entonces, no solo es más rápido porque puede pasar de un elemento al siguiente mediante la simple adición de puntero, posiblemente la operación más rápida que existe, sino que todos sus algoritmos agradables como búsqueda binaria, clasificación, etc. son fáciles de implementar en esta “colección indexada” “.

Si son de alto rendimiento y más fáciles de trabajar, ¿cuál es el inconveniente?

¿Recuerdas un poco acerca de ser ubicaciones de memoria contiguas? ¿Cuánta memoria tienes disponible? Digamos 10 conciertos. Ejecutas tu programa y asigna 10 matrices, cada una de tamaño 700 mb. Entonces, ¿ha asignado un total de 7 gb y le quedan 3 gb a la derecha? ¿Por qué no asignar el resto en una nueva matriz de 3 gb? Darle una oportunidad. ¡Vaya, obtienes un error de memoria insuficiente de malloc! ¿¿Pero por qué??

Sí, todavía tiene los 3 gbs disponibles, ¡pero no está disponible contiguamente ! Su diseño puede verse así:

700mb asignados – 300mb gratis – 700 asignados – 300 gratis – etc.

Como puede ver, ¡la memoria libre está fragmentada entre bloques de memoria usada!

La cantidad de memoria disponible para una matriz es una bestia más compleja. Es una función de memoria disponible y diseño de asignación de memoria. ¡La matriz máxima que podría asignar ahora sería 300 mb, no 3 gb!

Oh siento tus lágrimas Realmente solo necesitas usar toda esa memoria por la que pagaste. Realmente realmente necesitas esos últimos 3 gbs. Afortunadamente, Wellp tiene una solución, se llama la lista vinculada. ¡Podemos usar algo de humo y espejos, punteros y estructuras, para unir estos 10 bloques libres de memoria contigua! Por supuesto, ahora es un poco más complicado indexar esta lista y la contabilidad adicional tiene un costo de rendimiento, pero la ventaja es que en realidad nos permite usar la memoria fragmentada que pagamos para cargar colecciones más grandes.

Por supuesto, no tiene sentido vincular todos sus datos. No podrá asignar una nueva lista vinculada tan grande como una matriz debido a los punteros adicionales y la contabilidad necesarios. Estas cosas están destinadas a crecer dinámicamente.

En la práctica quieres los dos. Desea que los bloques rápidos contiguos estén unidos lógicamente. Por lo tanto, puede ejecutar algunos cálculos rápidos en un bloque, luego saltar a través de algunos enlaces, abrir otro bloque, etc. Es por eso que los árboles B son tan efectivos y son la base de las bases de datos relacionales. Son esencialmente bloques contiguos unidos lógicamente entre sí.

Para grandes cantidades de datos, querrá usar tanto memoria contigua como vinculada.

¿Recuerda las estructuras de datos de Stack and Queue y sus aplicaciones? Por lo general, se implementan como Listas vinculadas. ¿Por qué? Piense en la implementación basada en matriz de estas estructuras de datos. Ya verás por qué. (Creo que Stack se puede implementar fácilmente usando matrices. Pero es difícil implementar Colas con capacidad desconocida).

Las listas enlazadas son estructuras de datos fundamentales en lenguajes de programación funcional como Haskell, Scheme, etc.

Dato curioso : el antiguo sistema de archivos FAT utiliza listas enlazadas.

Déjame darte un simple resumen.

Los contactos en su teléfono se guardan en forma de una lista vinculada.

Explicación: Por un momento, considere que usa matrices para el mismo propósito. Imagine que tenemos algunos contactos guardados como Arun, Beiber, Raj, Sushant y Tarun. Tiene una matriz de tamaño 1000 que es el no máximo. de contactos que su teléfono puede almacenar. Ahora, si intenta guardar un nuevo contacto con el nombre Dhawan, la lista de operaciones debe realizarse:

  • Desplace todos los elementos después de ‘Beiber’ un paso hacia la derecha para crear espacio para almacenar ‘Dhawan’, ya que los contactos se almacenan en orden ordenado.
  • Regrese a la posición desde la que comenzó a cambiar e inserte Dhawan.

La operación de cambio es muy costosa en términos de tiempo. Si usamos una lista vinculada para el mismo. Simplemente podemos crear un nuevo nodo que contenga el nombre Dhawan y ajustar los enlaces para insertarlo en la lista de enlaces. Esto definitivamente consume menos tiempo.

Espero que esto ayude 🙂

No siempre es cierto que tengamos que usar LinkedList sobre matrices. Claramente, depende de su CASO DE USO.

¿Cuándo usar Linked List?

  • Cuando no tiene un tamaño fijo de su matriz. El tamaño de su matriz cambia dinámicamente.
  • Cuando tiene que hacer mucha inserción y eliminación en sus datos.

¿Cuándo usar matrices?

  • Cuando tiene que acceder a cada elemento de la matriz, es decir, la matriz transversal.
  • Cuando tienes un pequeño conjunto de datos.
  • Cuando su preocupación es mejor la localidad de caché.
  • Cuando tienes que ahorrar espacio en la memoria. Dado que agregar nodos para guardar direcciones agrega espacio adicional a la memoria.
  • Ejemplo: al implementar la búsqueda.

El costo de inserción y eliminación en una matriz es mayor que en la lista vinculada. Para insertar algo en la matriz, primero debemos empujar todos los elementos desde esa posición a un paso adelante, y luego insertar lo que queramos.

Pero, en la lista vinculada, es fácil eliminar la inserción, ya que solo necesitamos señalar el nodo a una dirección entre la lista para la inserción.

El siguiente enlace explica en detalle los puntos anteriores:

Lista vinculada vs matriz – GeeksforGeeks

Mire el siguiente enlace para obtener una buena visión del caso de uso del mundo real de la Lista vinculada y las matrices.

ejemplos del mundo real donde se usa linklist sobre array y viceversa. – GeeksforGeeks Q&A

Si necesita insertar o eliminar elementos en el medio o al principio (por lo tanto, básicamente, todo excepto el final), en una lista vinculada esto es solo una asignación y un par de actualizaciones de puntero, mientras que en una matriz puede que tenga que mueva todos los elementos que vienen después del punto donde realizó la modificación (y es posible que necesite hacer crecer la matriz; supongo que está utilizando matrices dinámicas aquí).

Pero, en general, debido a la forma en que funcionan las CPU modernas, de hecho la solución más derrochadora a veces resulta ser más rápida: copiar memoria secuencial a otra dirección en realidad no es un gran problema para la CPU, sino la aleatoriedad introducida al seguir los punteros en el lista vinculada es . Así que hoy, incluso si el libro de texto dice que para alguna tarea una lista vinculada es más rápida, probablemente sea mejor no confiar en eso y probarlo con la solución “tonta” con matrices y elementos móviles. Especialmente si tienes mucha más lectura que actualización.

PD: si no le importa el orden de los elementos, hay un truco para eliminar elementos en el medio que no mueve todos los elementos: simplemente cambie el elemento que desea eliminar con el último, luego elimine el último (eliminando al final a menudo solo se actualiza el puntero de relleno).

Esta es nuevamente una de las preguntas en las que muchos de los entrevistados se confundieron.

Principalmente, uno querría usar ArrayList en los casos en que existe una mayor necesidad de acceder al elemento en lugar de la inserción o eliminación. Por otro lado, uno desearía usar LinkedList cuando hay una mayor necesidad de inserción y eliminación y no se usa mucho el acceso al elemento en un índice particular.

Esto se debe principalmente a que la peor complejidad de tiempo para acceder a un elemento / objeto en una ArrayList siempre es “1? mientras que en LinkedList puede ser “n”.

En caso de adición o eliminación de elementos en una ArrayList, hay una operación como System.arraycopy está involucrada. Esta es una operación bastante costosa y, por lo tanto, en los casos de uso en los que están involucradas la inserción y eliminación frecuentes de elementos, se prefiere LinkedList donde se trata de agregar o eliminar el nodo y volver a vincular el nodo existente.

“Conozco la complejidad de varias operaciones y sus comparaciones. Pero a pesar de todo eso, no puedo entender los beneficios del mundo real de esto “.

Esto solo me confundió. Si conoce las comparaciones de complejidad, entonces debería estar discutiendo por qué cree que estas complejidades no se traducen en beneficios del mundo real.

  1. Si necesita consultar repetidamente datos ordenados, entonces la operación será de órdenes de magnitud más rápido en una matriz que en una lista vinculada, porque puede realizar una búsqueda binaria rápida.
  2. Supongamos que realiza una operación `get` que devuelve el elemento en un índice. Supongamos que hace esto 1 millón de veces, en una lista de 1 millón de entradas, índices de consulta distribuidos aleatoriamente de 0 a 999,999.

    Para una lista vinculada, en promedio, este conjunto de operaciones tomará ~ 500,000 veces más que en una matriz. Esa puede ser la diferencia entre 1 microsegundo y 5 segundos, o 1 segundo y … 6 días. Incluso para programas pequeños, puede significar la diferencia entre imperceptible y notable.

Estoy de acuerdo, para la mayoría de las cosas del día a día, probablemente no necesite pensar en esto, como cuando escribe una aplicación o algo así. Pero, debido a las buenas opciones de diseño, estas mejoras están presentes bajo el capó en los lugares correctos, y están acelerando casi todas las piezas de software que utilizamos.

Considera lo siguiente.

Una matriz necesita una asignación y una copia para crecer, a diferencia de una lista vinculada. Una sobrecarga pequeña pero potencialmente crítica en ciertas circunstancias.

Eres un pasajero en un avión. ¿Preferiría que el software que controla su avión en la aproximación final haya implementado sus estructuras críticas en tiempo real utilizando matrices o listas vinculadas?

De acuerdo, desea beneficios del mundo real en la lista vinculada, primero veamos cuáles son los pros y los contras de usar la lista vinculada.

Pros:

La gestión eficiente de la memoria, lo que quiero decir es que la eliminación del elemento en cualquier lugar de la lista vinculada no puede dejar ninguna memoria asignada y lo mismo sucede con la inserción.

Contras:

Como se trata de una estructura de datos lineal y una búsqueda no basada en índices para el elemento en la lista vinculada, es más lento.

Ahora llega a la aplicación del mundo real, solo reproduce una lista de reproducción en Windows Media Player.

Puedes agregar una canción más a tu lista de reproducción sin dudarlo y también puedes eliminarla. (Lista enlazada individual)

Mientras reproduce la lista de reproducción, puede pasar a la canción anterior y también a la siguiente. Si desea reproducir la canción anterior, simplemente presione el botón anterior a la derecha. Esto no es más que una lista de doble enlace.

Si desea un ejemplo de matriz, piense en la partición del disco. Una vez que haya realizado la partición del disco, no puede agregar más espacio al espacio en el disco (estoy hablando de la asignación del espacio en el disco al instalar el sistema operativo). Después de algún tiempo, si desea más espacio, debe copiar todo el contenido en el espacio de disco en particular, luego reestructurar la partición del disco con más espacio en disco y volver a copiar todo el contenido donde desee.

Espero que mi respuesta haya ayudado un poco para lo que estás buscando.

Debe usar LinkedList si tiene que cambiar el orden de los nodos con frecuencia, como insertar nuevos nodos o eliminar nodos en el medio de la lista. La complejidad de tiempo de inserción y eliminación para LinkedList es O (1) y la complejidad de tiempo para acceder a un elemento en LinkedList es O (n). Entonces, si valora más la inserción y eliminación que acceder a un elemento, debe usar LinkedList.

La matriz es una memoria asignada continua. Entonces, esencialmente obtienes O (1) complejidad al acceder a un elemento, lo que significa que puedes acceder aleatoriamente a cualquier elemento de la matriz rápidamente. Sin embargo, al eliminar o insertar un elemento en el medio de la matriz, debe copiar un bloque de memoria grande que resulta en una complejidad O (n).

No hay beneficios por usar listas enlazadas. Las listas enlazadas son bastante malas y deben evitarse. Las matrices siempre funcionarán mejor que las listas vinculadas. ¿Por qué?

Localidad.

En el hardware moderno, la localidad de caché es tan importante como los ciclos. Las matrices son muy amigables con la caché donde las listas no lo son, los elementos en una matriz se encuentran uno al lado del otro en la memoria principal, por lo que cuando la CPU carga sus palabras, se benefician enormemente de la localidad espacial / temporal. Por un lado, las listas vinculadas con demasiados punteros que apuntan a áreas disjuntas de memoria de memoria causarían una gran cantidad de indirección de puntero.

Los gráficos muestran la comparación de la complejidad del espacio de ArrayList y LinkedList, pero en el mundo real le preocuparía menos la complejidad del espacio en comparación con la complejidad del tiempo, así que veamos la comparación de la complejidad del tiempo de diferentes operaciones.

  • La inserción o eliminación al principio o en el medio es una operación de tiempo de contacto en LinkedList, mientras que en ArrayList cuando desea insertar o eliminar desde el medio, entonces tiene que cambiar todos los elementos después de que el elemento eliminado o insertado tiene la peor complejidad de tiempo de O ( norte).
  • La inserción al final de esta operación también tiene una complejidad de tiempo constante para LinkedList y la peor complejidad de tiempo O (n) para ArrayList porque ArrayList tiene un tamaño dinámico, lo que significa que el tamaño inicial de ArrayList se fija ahora siempre que sea necesario aumentar el tamaño de ArrayList más de su capacidad. Los elementos de la ArrayList actual se copian a una nueva ArrayList cuyo tamaño es 1.5 veces más. Pero la complejidad promedio de esta operación es mucho menor.
  • El acceso al elemento es una operación de tiempo constante para ArrayList porque puede acceder a cualquier elemento usando su índice, mientras que en LinkedList necesita iterar sobre la Lista completa para encontrar el elemento, por lo que la complejidad del tiempo en el peor de los casos sería O (n).

Por lo tanto, debe decidir a partir de esto qué desea lograr si su programa necesita un alto número de inserción y eliminación, entonces LinkedList sería bueno, pero cuando necesite acceder a elementos aleatoriamente con mucha frecuencia, usará ArrayList. Para la búsqueda también se preferiría ArrayList sobre LinkedList porque si está ordenado puede realizar una búsqueda binaria. Pero tenga en cuenta que para buscar hay una mejor estructura de datos que LinkedList y ArrayList, como el árbol de búsqueda binario o la tabla hash.

More Interesting

¿Qué marco o arquitectura de software tuvo un profundo impacto en el desarrollo de su producto de software y por qué?

En Go, ¿qué es un objeto de paquete instalado?

¿Cuál es la mejor herramienta para implementar indicadores de características en mi empresa?

¿La inteligencia artificial llegará a un punto en el que los codificadores pierdan su demanda en el mundo de los trabajos tecnológicos?

¿Puede desarrollar una competencia decente en sistemas distribuidos por su cuenta en su computadora portátil o necesita una infraestructura distribuida real para jugar?

¿Cuáles son algunas startups que se centran en productos para desarrolladores?

¿Por qué los servicios de desarrollo de software offshore se están volviendo populares?

¿Cuál es el mejor campo de desarrollo de software para perseguir?

¿Puede escuchar audiolibros mientras programa?

¿La decisión de Sony de retirarse de DRM está alejando a los desarrolladores y editores externos?

¿Qué tan fácil en Estados Unidos para un desarrollador de software una vez terminado para encontrar un nuevo trabajo?

Cómo seguir siendo competente en múltiples lenguajes y tecnologías de programación si su trabajo solo requiere uno

Para aprender Objective-J, ¿con qué otras fuentes es mejor comenzar aparte del sitio web Cappuccino?

¿Qué tipo de desarrolladores de software todavía usan C?

¿Cuáles son las 10 principales compañías para comenzar su carrera como desarrollador de software para nuevos en la India?