claudio
¿Cuál es la forma más fácil de usar una lista vinculada en Python? En Scheme, una lista enlazada se define simplemente por '(1 2 3 4 5)
.
listas de Python, [1, 2, 3, 4, 5]
y tuplas, (1, 2, 3, 4, 5)
, no son, de hecho, listas enlazadas, y las listas enlazadas tienen algunas buenas propiedades, como la concatenación en tiempo constante y la posibilidad de hacer referencia a partes separadas de ellas. ¡Hazlos inmutables y es muy fácil trabajar con ellos!
Ber
Para algunas necesidades, un deque también puede ser útil. Puede agregar y eliminar elementos en ambos extremos de una deque a un costo de O (1).
from collections import deque
d = deque([1,2,3,4])
print d
for x in d:
print x
print d.pop(), d
-
Tiempo
deque
es un tipo de datos útil, no es una lista enlazada (aunque se implementa utilizando una lista doblemente enlazada en el nivel C). Entonces responde a la pregunta “¿qué usarías en lugar de listas vinculadas en Python?” y, en ese caso, la primera respuesta debería ser (para algunas necesidades) una lista ordinaria de Python (tampoco es una lista vinculada).– jfs
19/10/2013 a las 20:26
-
@JFSebastian: Casi estoy de acuerdo contigo 🙂 Creo que la pregunta que responde es más bien: “¿Cuál es la forma pitónica de resolver un problema que usa una lista vinculada en otros idiomas”. No es que las listas enlazadas no sean útiles, es solo que los problemas en los que un deque no funciona son muy raros.
– Emil Stenström
20/10/2013 a las 20:46
-
No tiene nada que ver con “Pythonic”: una lista enlazada es una estructura de datos diferente a una deque, y en las diversas operaciones que admiten los dos, tienen diferentes tiempos de ejecución.
– Tánatos
7 abr 2014 a las 20:48
-
@dimo414: las listas vinculadas generalmente prohíben la indexación (no
linked_list[n]
) porque sería O(n). Los dequeues lo permiten y lo ejecutan en O(1). Sin embargo, las listas enlazadas, dado un iterador en la lista, pueden permitir la inserción y eliminación de O(1), mientras que deques no (es O(n), como un vector). (Excepto al principio y al final, donde tanto los deques como las listas enlazadas son O(1). (aunque es probable que el deque esté amortizado como O(1). La lista enlazada no lo está).– Tánatos
19 de julio de 2014 a las 6:39
-
@MadPhysicist “Eso [deque] se comporta como una lista enlazada en casi todos los sentidos, incluso si el nombre es diferente”. — es incorrecto o no tiene sentido: es incorrecto porque las listas enlazadas pueden proporcionar diferentes garantías para las complejidades del tiempo, por ejemplo, puede eliminar un elemento (posición conocida) de una lista enlazada en O(1) mientras que deque no lo promete (no es
O(n)
). Si “casi todas las formas” permite ignorar la diferencia en O grande, entonces su declaración no tiene sentido porque podríamos usar una lista incorporada de Python como una deque si no fuera por las garantías pop (0), insert (0, v) O grande .– jfs
13/09/2016 a las 11:20
Nick Stinemates
esto lo escribi el otro dia
#! /usr/bin/env python
class Node(object):
def __init__(self):
self.data = None # contains the data
self.next = None # contains the reference to the next node
class LinkedList:
def __init__(self):
self.cur_node = None
def add_node(self, data):
new_node = Node() # create a new node
new_node.data = data
new_node.next = self.cur_node # link the new node to the 'previous' node.
self.cur_node = new_node # set the current node to the new one.
def list_print(self):
node = self.cur_node # cant point to ll!
while node:
print node.data
node = node.next
ll = LinkedList()
ll.add_node(1)
ll.add_node(2)
ll.add_node(3)
ll.list_print()
-
¿Cómo podría revisar la lista y buscar un nodo específico con datos específicos?
– loco
25 de agosto de 2011 a las 17:17
-
@locoboy el código para hacer eso sería similar en lógica al código en
list_print()
.-Dennis
11 de diciembre de 2013 a las 19:28
-
Muestra la lista en orden inverso
– usuario9652688
20 oct 2019 a las 0:50
jfs
Aquí hay algunas funciones de lista basadas en la representación de Martin v. Löwis:
cons = lambda el, lst: (el, lst)
mklist = lambda *args: reduce(lambda lst, el: cons(el, lst), reversed(args), None)
car = lambda lst: lst[0] if lst else lst
cdr = lambda lst: lst[1] if lst else lst
nth = lambda n, lst: nth(n-1, cdr(lst)) if n > 0 else car(lst)
length = lambda lst, count=0: length(cdr(lst), count+1) if lst else count
begin = lambda *args: args[-1]
display = lambda lst: begin(w("%s " % car(lst)), display(cdr(lst))) if lst else w("nil\n")
donde w = sys.stdout.write
Aunque las listas doblemente enlazadas son famosamente utilizadas en el libro de Raymond Hettinger receta ordenadalas listas enlazadas individualmente no tienen ningún valor práctico en Python.
He Nunca usó una lista enlazada individualmente en Python para cualquier problema, excepto educativo.
Thomas Watnedal sugirió un buen recurso educativo Cómo pensar como un científico informático, Capítulo 17: Listas enlazadas:
Una lista enlazada es:
- la lista vacía, representada por Ninguno, o
-
un nodo que contiene un objeto de carga y una referencia a una lista enlazada.
class Node: def __init__(self, cargo=None, next=None): self.car = cargo self.cdr = next def __str__(self): return str(self.car) def display(lst): if lst: w("%s " % lst) display(lst.cdr) else: w("nil\n")
-
Usted dice: nunca ha usado una lista enlazada individualmente en Python para ningún problema, excepto educativo. Eso es bueno para usted 🙂 Pero puedo asegurarle: HAY problemas en el mundo real donde una lista vinculada proporcionará una solución ideal 🙂 Es por eso que busqué listas vinculadas en StackOverflow en primer lugar 🙂
– Regis mayo
27/01/2017 a las 21:30
-
@RegisMay: ¿le importaría proporcionar un enlace a un ejemplo de código práctico específico? (nota: debe ser “una lista enlazada individualmente en Python” “En el mundo real”: describa los beneficios para su ejemplo, por ejemplo, legibilidad, rendimiento u otro “valor práctico” de su elección). Hice una solicitud similar en el pasado: en 8 años, cero enlaces, excepto las listas doblemente enlazadas que se usan en la receta del conjunto ordenado de Raymond Hettinger; tal vez, podría explicarse que solo los programadores nuevos en Python leen esta pregunta: su aporte Sería valioso y muy apreciado.
– jfs
27 de enero de 2017 a las 22:02
-
Oh, lo siento. No soy un hablante nativo de inglés y confundí “una lista de enlaces únicos” con “una lista de enlaces únicos”. Sin embargo, necesito una lista enlazada (doble), que no existe en python. Un deque no ayuda, ya que necesito acceso directo a cada elemento individual sin iterar sobre todos los elementos. Mi objetivo: quiero implementar un caché. Sin embargo: si mi imperfección en el idioma inglés hace que mis comentarios estén fuera de lugar, elimine estos comentarios. Perdón por cualquier inconveniente.
– Regis mayo
29/01/2017 a las 19:00
-
Una ventaja práctica de una lista enlazada individualmente sobre las listas o matrices doblemente enlazadas (que Python usa internamente para las listas) es que dos listas enlazadas pueden compartir una cola. Esto es muy útil para algoritmos dinámicos que requieren valores guardados de iteraciones anteriores donde compartir colas de listas puede reducir la complejidad de la memoria de cuadrática a lineal y eliminar la sobrecarga de tiempo debido a la copia.
– Saolof
25 de junio de 2017 a las 12:08
-
Ese enlace de rosettacode estaba un ejemplo del mundo real, que utiliza una lista vinculada simulada en lugar de una lista vinculada real. Mírelo, reescríbalo para usar una lista enlazada real, para mejorar la claridad y la legibilidad, y ahí tiene el ejemplo del mundo real de una lista enlazada que se usa para mejorar el código existente. Y, en segundo lugar, el algoritmo de subsecuencia creciente más largo se usa en el mundo real, en estadísticas, así que ahí lo tienen. QED :). Más allá de eso, aceptemos estar en desacuerdo. 🙂
– Gino
26/09/2017 a las 21:06
cris redford
La respuesta aceptada es bastante complicada. Aquí hay un diseño más estándar:
L = LinkedList()
L.insert(1)
L.insert(1)
L.insert(2)
L.insert(4)
print L
L.clear()
print L
es un sencillo LinkedList
clase basada en el sencillo diseño de C++ y Capítulo 17: Listas enlazadassegún lo recomendado por Thomas Watnedal.
class Node:
def __init__(self, value = None, next = None):
self.value = value
self.next = next
def __str__(self):
return 'Node ['+str(self.value)+']'
class LinkedList:
def __init__(self):
self.first = None
self.last = None
def insert(self, x):
if self.first == None:
self.first = Node(x, None)
self.last = self.first
elif self.last == self.first:
self.last = Node(x, None)
self.first.next = self.last
else:
current = Node(x, None)
self.last.next = current
self.last = current
def __str__(self):
if self.first != None:
current = self.first
out="LinkedList [\n" +str(current.value) +'\n'
while current.next != None:
current = current.next
out += str(current.value) + '\n'
return out + ']'
return 'LinkedList []'
def clear(self):
self.__init__()
Las listas inmutables se representan mejor a través de dos tuplas, con None representando NIL. Para permitir una formulación simple de tales listas, puede usar esta función:
def mklist(*args):
result = None
for element in reversed(args):
result = (element, result)
return result
Para trabajar con tales listas, prefiero proporcionar la colección completa de funciones LISP (es decir, primera, segunda, enésima, etc.), que introducir métodos.
Aquí hay una versión un poco más compleja de una clase de lista enlazada, con una interfaz similar a los tipos de secuencia de python (es decir, admite indexación, división, concatenación con secuencias arbitrarias, etc.). Debe tener O (1) antepuesto, no copia datos a menos que sea necesario y se puede usar de manera bastante intercambiable con tuplas.
No será tan eficiente en el espacio o el tiempo como las celdas de cons de lisp, ya que las clases de python obviamente son un poco más pesadas (podría mejorar las cosas ligeramente con “__slots__ = '_head','_tail'
” para reducir el uso de memoria). Sin embargo, tendrá las características de rendimiento deseadas de gran O.
Ejemplo de uso:
>>> l = LinkedList([1,2,3,4])
>>> l
LinkedList([1, 2, 3, 4])
>>> l.head, l.tail
(1, LinkedList([2, 3, 4]))
# Prepending is O(1) and can be done with:
LinkedList.cons(0, l)
LinkedList([0, 1, 2, 3, 4])
# Or prepending arbitrary sequences (Still no copy of l performed):
[-1,0] + l
LinkedList([-1, 0, 1, 2, 3, 4])
# Normal list indexing and slice operations can be performed.
# Again, no copy is made unless needed.
>>> l[1], l[-1], l[2:]
(2, 4, LinkedList([3, 4]))
>>> assert l[2:] is l.next.next
# For cases where the slice stops before the end, or uses a
# non-contiguous range, we do need to create a copy. However
# this should be transparent to the user.
>>> LinkedList(range(100))[-10::2]
LinkedList([90, 92, 94, 96, 98])
Implementación:
import itertools
class LinkedList(object):
"""Immutable linked list class."""
def __new__(cls, l=[]):
if isinstance(l, LinkedList): return l # Immutable, so no copy needed.
i = iter(l)
try:
head = i.next()
except StopIteration:
return cls.EmptyList # Return empty list singleton.
tail = LinkedList(i)
obj = super(LinkedList, cls).__new__(cls)
obj._head = head
obj._tail = tail
return obj
@classmethod
def cons(cls, head, tail):
ll = cls([head])
if not isinstance(tail, cls):
tail = cls(tail)
ll._tail = tail
return ll
# head and tail are not modifiable
@property
def head(self): return self._head
@property
def tail(self): return self._tail
def __nonzero__(self): return True
def __len__(self):
return sum(1 for _ in self)
def __add__(self, other):
other = LinkedList(other)
if not self: return other # () + l = l
start=l = LinkedList(iter(self)) # Create copy, as we'll mutate
while l:
if not l._tail: # Last element?
l._tail = other
break
l = l._tail
return start
def __radd__(self, other):
return LinkedList(other) + self
def __iter__(self):
x=self
while x:
yield x.head
x=x.tail
def __getitem__(self, idx):
"""Get item at specified index"""
if isinstance(idx, slice):
# Special case: Avoid constructing a new list, or performing O(n) length
# calculation for slices like l[3:]. Since we're immutable, just return
# the appropriate node. This becomes O(start) rather than O(n).
# We can't do this for more complicated slices however (eg [l:4]
start = idx.start or 0
if (start >= 0) and (idx.stop is None) and (idx.step is None or idx.step == 1):
no_copy_needed=True
else:
length = len(self) # Need to calc length.
start, stop, step = idx.indices(length)
no_copy_needed = (stop == length) and (step == 1)
if no_copy_needed:
l = self
for i in range(start):
if not l: break # End of list.
l=l.tail
return l
else:
# We need to construct a new list.
if step < 1: # Need to instantiate list to deal with -ve step
return LinkedList(list(self)[start:stop:step])
else:
return LinkedList(itertools.islice(iter(self), start, stop, step))
else:
# Non-slice index.
if idx < 0: idx = len(self)+idx
if not self: raise IndexError("list index out of range")
if idx == 0: return self.head
return self.tail[idx-1]
def __mul__(self, n):
if n <= 0: return Nil
l=self
for i in range(n-1): l += self
return l
def __rmul__(self, n): return self * n
# Ideally we should compute the has ourselves rather than construct
# a temporary tuple as below. I haven't impemented this here
def __hash__(self): return hash(tuple(self))
def __eq__(self, other): return self._cmp(other) == 0
def __ne__(self, other): return not self == other
def __lt__(self, other): return self._cmp(other) < 0
def __gt__(self, other): return self._cmp(other) > 0
def __le__(self, other): return self._cmp(other) <= 0
def __ge__(self, other): return self._cmp(other) >= 0
def _cmp(self, other):
"""Acts as cmp(): -1 for self<other, 0 for equal, 1 for greater"""
if not isinstance(other, LinkedList):
return cmp(LinkedList,type(other)) # Arbitrary ordering.
A, B = iter(self), iter(other)
for a,b in itertools.izip(A,B):
if a<b: return -1
elif a > b: return 1
try:
A.next()
return 1 # a has more items.
except StopIteration: pass
try:
B.next()
return -1 # b has more items.
except StopIteration: pass
return 0 # Lists are equal
def __repr__(self):
return "LinkedList([%s])" % ', '.join(map(repr,self))
class EmptyList(LinkedList):
"""A singleton representing an empty list."""
def __new__(cls):
return object.__new__(cls)
def __iter__(self): return iter([])
def __nonzero__(self): return False
@property
def head(self): raise IndexError("End of list")
@property
def tail(self): raise IndexError("End of list")
# Create EmptyList singleton
LinkedList.EmptyList = EmptyList()
del EmptyList
llist — Tipos de datos de listas enlazadas para Python
El módulo llist implementa estructuras de datos de listas enlazadas. Admite una lista doblemente enlazada, es decir dllist
y una estructura de datos de enlace simple sllist
.
objetos de lista dll
Este objeto representa una estructura de datos de lista doblemente enlazada.
first
Primero dllistnode
objeto en la lista. None
si la lista está vacía.
last
Ultimo dllistnode
objeto en la lista. Ninguno si la lista está vacía.
Los objetos dllist también admiten los siguientes métodos:
append(x)
Agregar x
al lado derecho de la lista y volver insertado dllistnode
.
appendleft(x)
Agregar x
al lado izquierdo de la lista y volver insertado dllistnode
.
appendright(x)
Agregar x
al lado derecho de la lista y volver insertado dllistnode
.
clear()
Elimina todos los nodos de la lista.
extend(iterable)
Agregar elementos de iterable
al lado derecho de la lista.
extendleft(iterable)
Agregar elementos de iterable
al lado izquierdo de la lista.
extendright(iterable)
Agregar elementos de iterable
al lado derecho de la lista.
insert(x[, before])
Agregar x
al lado derecho de la lista si before
no se especifica, o insertar x
al lado izquierdo de dllistnode before
. Devolución insertada dllistnode
.
nodeat(index)
Nodo de retorno (de tipo dllistnode
) a index
.
pop()
Elimina y devuelve el valor de un elemento del lado derecho de la lista.
popleft()
Elimina y devuelve el valor de un elemento del lado izquierdo de la lista.
popright()
Eliminar y devolver el valor de un elemento del lado derecho de la lista
remove(node)
Eliminar node
de la lista y devolver el elemento que se almacenó en él.
dllistnode
objetos
clase llist.dllistnode([value])
Devuelve un nuevo nodo de lista doblemente enlazado, inicializado (opcionalmente) con value
.
dllistnode
Los objetos proporcionan los siguientes atributos:
next
Siguiente nodo en la lista. Este atributo es de solo lectura.
prev
Nodo anterior en la lista. Este atributo es de solo lectura.
value
Valor almacenado en este nodo.
Compilado de esta referencia
lista
clase llist.sllist([iterable])
Devuelve una nueva lista enlazada individualmente inicializada con elementos de iterable
. Si no se especifica iterable, el nuevo sllist
esta vacio.
Se define un conjunto similar de atributos y operaciones para este sllist
objeto. Consulte esta referencia para obtener más información.
-
¿Hay una fuente para esto? ¿Funciona para python3?
– iggy12345
16 mayo 2019 a las 20:32
Esto te puede ayudar a visualizarlo… pythontutor.com/…
– usuario1889082
9 de diciembre de 2012 a las 7:41
@ usuario1889082 impresionante! realmente me ayuda a entender algunos conceptos de python
– Jerry An
19 de diciembre de 2020 a las 14:19