Operaciones en Listas Enlazadas: Búsqueda, Inserción y Eliminación
Resumen
¿Cómo se manejan las estructuras de datos con nodos?
Entender las operaciones en estructuras de datos como las listas enlazadas puede parecer complicado al principio. Para abordar este desafío, necesitamos un profundo conocimiento de cómo operar, qué herramientas usar y cómo implementarlas adecuadamente. Este artículo explorará el funcionamiento conceptual de las operaciones comunes en listas enlazadas simples, resaltando la importancia de comprender cómo se manipulan los nodos.
¿Qué papel juegan las variables auxiliares?
Las variables auxiliares, como la utilizada en este caso, denominada prop, son fundamentales. Estas variables nos permiten conocer qué hay dentro de cada nodo mientras recorremos la lista. Durante este proceso, los nodos se recorren mediante un bucle while hasta que se cumplen ciertas condiciones que permiten detenerse para realizar modificaciones necesarias en los datos.
¿Cómo se realizan las operaciones básicas en listas enlazadas?
Hay varias operaciones básicas que se pueden realizar en una lista enlazada:
Búsqueda: Nuestra variable prop visita cada nodo en búsqueda de un valor específico. Si buscamos el elemento con valor dos, por ejemplo, el procedimiento se detiene cuando se encuentra el valor, anunciándonos su localización.
Reemplazo: Este método permite dar un argumento, buscarlo y reemplazarlo. Al buscar el nodo con valor tres y reemplazarlo por una letra, como ‘f’, la lista se altera introduciendo un nuevo elemento.
Inserción al inicio: Para insertar un nuevo nodo al principio, ese nodo se convierte en el nuevo head, mientras que el anterior head se pasa al segundo lugar.
Inserción al final: Para añadir un nodo al final, identificamos el tail, que apunta a null, y actualizamos la lista para incluir nuestro nueva entrada al final.
¿Cómo se eliminan nodos en listas enlazadas?
Eliminar nodos requiere cuidado, especialmente cuando hay valores duplicados. Es crucial localizar y señalar el nodo que queremos eliminar considerando los atributos next, head y tail para evitar confusiones. Es importante documentar bien el código para tener claridad sobre la cantidad de nodos y los datos que almacena cada uno, evitando así el caos en la gestión de nodos.
¿Qué complejidades adicionales presentan las listas enlazadas?
Aumentar la complejidad de las operaciones es posible trabajando no solo con head o tail, sino también con nodos intermedios. Al insertar un nodo en una posición específica, por ejemplo, es importante entender cómo reposicionar los punteros de nodo.
Las manipulaciones intermedias, como eliminar un nodo en una posición intermedia, requieren recorridos cuidadosos y ajustes de las referencias de nodo anteriores y siguientes.
Ejemplo de inserción intermedia
Si insertamos un nodo en una posición intermedia, se debe calcular exactamente dónde se va a ubicar. A continuación, el nuevo nodo también debe apuntar a su nodo siguiente correcto, asegurando que la estructura de la lista se mantenga coherente.
# Supongamos que estamos manejando una lista enlazada en Python# Insertar un nodo en una posición intermedia podría parecerse a esto:classNodo:def__init__(self, data): self.data = data
self.next=Nonedefinsertar_en_medio(head, dato_nuevo, valor_anterior): nuevo_nodo = Nodo(dato_nuevo) actual = head
while actual isnotNoneand actual.data != valor_anterior: actual = actual.nextif actual isnotNone: nuevo_nodo.next= actual.next actual.next= nuevo_nodo
Este ejemplo demuestra cómo un nuevo nodo se integra en una posición intermedia fijando conexiones entre nodos vecinos.
¿Qué sucede con estructuras más complejas como las listas circulares?
A lo largo de este análisis hemos descrito listas enlazadas de vía única, pero existen variaciones como las listas circulares que se comportan de manera diferente, ya que el último nodo apunta de nuevo al primer nodo. Este es apenas el comienzo de entender la complejidad que ofrecen las diferentes estructuras de datos en programación. Invitamos a continuar explorando y aprendiendo sobre estas fascinantes arquitecturas para dominar el mundo de la informática.
from nodos importNodeclassSinglyLinkedList: def __init__(self): self.head=None self.size=0 def add_to_start(self, data):"""Inserta un nodo al inicio.""" self.head=Node(data, self.head)print(f"Nodo {self.head.data} añadido a la cabezera.") self.size+=1 def append(self, data):"""Añade un nodo nuevo al final.""" node =Node(data)if self.head==None: self.head= node
else: probe = self.headwhile probe.next: probe = probe.next probe.next= node
print(f"Nodo {node.data} añadido a la cola.") self.size+=1 def insert(self, data, index):"""Inserta un nodo segun indice."""if index > self.count_nodes():print("El indice supera la cantidad de nodos")else:if self.head is None or index <=0: self.head=Node(data, self.head)else: probe = self.head index -=1while index >1 and probe.next!=None: probe = probe.next index -=1 probe.next=Node(data, probe.next)print(f"Nodo {data} añadido.") self.size+=1 def replace(self, data, new_data):"""Reemplaza un nodo por uno nuevo.""" probe = self.headwhile probe !=None and data != probe.data: probe = probe.nextif probe !=None: probe.data= new_data
print(f"El nodo {data} ha sido reemplazado por {new_data}")else:print(f"The target item {data} is not in the linked list") def delete(self, index):"""Elimina nodo en posición dada."""if index > self.count_nodes():print("El indice supera la cantidad de nodos")else:if self.head is None:print("No hay nodos que eliminar.") elif self.head.next is None:print(f"Nodo: {self.head.data} eliminado.") self.head=None self.size-=1else: probe = self.head index -=1while index >1 and probe.next.next!=None: probe = probe.next index -=1 removed_item = probe.next.data probe.next= probe.next.nextprint(f"Nodo:{removed_item} eliminado.") self.size-=1 def pop(self):"""Elimina ultimo nodo.""" data = self.head.dataif self.head.next is None: self.head=Noneelse: probe = self.headwhile probe.next.next!=None: probe = probe.next data = probe.next.data probe.next=None self.size-=1print(f"Ultimo nodo {data} eliminado.") def search(self, data):"""Busca nodo especificado.""" probe = self.headwhile probe !=None and data != probe.data: probe = probe.nextif probe !=None:print(f"El nodo {data} ha sido encontrado.")return probe
else:print(f"El nodo {data} no se encuentra en el grafo.") def count_nodes(self):"""Imprime cantidad de nodos."""return self.size def print(self):"""Imprime cada nodo.""" probe = self.headwhile probe !=None:print(probe.data) probe = probe.next def clear(self): self.head=None self.size=0
Solo falto el método iter, pero muy bueno, gracias!
Muchas gracias por tu aporte.
Mi aporte:
¿Qué editor usaste?
Hola Jose Carlos, es VSC con una extensión para hacer imagenes del código
LinkedList con todos los métodos de List.
Implementé todos los métodos de list a mi clase de linked list, de forma que pueden usar los mismos métodos y sintaxis que usan para manipular una lista normal.
Incluyendo el
Código
SinglyLinkedList
from typing import Any
from typing import Optional
from typing import Iterator
from typing import Union
from typing import Iterable
from node import Node
classSinglyLinkedList:"""Singly Linked List""" _head: Optional[Node] _tail: Optional[Node] _size:intdef__init__(self,*items)->None:"""Initialize an empty list
Args:
*items: Items to be added to the list.
""" self._head =None self._tail =None self._size =0iflen(items)==1andisinstance(items[0],(Iterable, SinglyLinkedList)): items = items[0]for item in items: self.append(item)@propertydefsize(self):"""Returns the size of the linked list.
Time complexity: O(1)
"""return self._size
defclear(self):"""Clears the list.
Removes all the items inside the list.
""" self._head =None self._size =0defcopy(self):"""Returns a copy of the list.
Time Complexity: O(1)
""" new_list = SinglyLinkedList()if self._head isnotNone:# Caution: This is a shallow copy new_list._head = self._head
new_list._size = self._size
return new_list
defdepthcopy(self)->'SinglyLinkedList':"""Returns a copy of the list and its nodes.
Time complexity: O(n)
Returns:
SinglyLinkedList: Copy of the list.
""" new_list = SinglyLinkedList()for item in self: new_list.append(item.value)return new_list
defappend(self, value: Any):"""Appends a new value at the end of the list.
Time complexity: O(1)
""" node = Node(value)if self._head isNone: self._head = node
self._tail = self._head
else: self._tail.next= Node(value) self._tail = self._tail.next self._size +=1defextend(self, other: Iterable):"""Extends the current list with the provided list.
Time complexity: O(n) where n is the length of the list to extend.
Args:
other: List to be extended.
"""for item in other:ifisinstance(other, Node): self.append(item.value)else: self.append(item)defpop(self, index:int=-1)-> Any:"""Removes an item from the list.
Raises IndexError if the list is empty or index is out of range.
Time complexity: O(n) where n is the length of the nodes.
Args:
index: Index of the item to be removed.
Returns:
Any: Item removed.
"""if index <0: index = self._size + index
if self._head isNoneor index > self._size -1:raise IndexError('Index out of range.') prev_pointer = self._head
value: Node
for idx, value inenumerate(self):if idx == index:if value == self._head: self._head =None self._tail =Noneelse: prev_pointer.next= value.next self._tail = prev_pointer
self._size -=1return value
prev_pointer = value
defindex(self, target:object):"""Return first index of value.
Raises ValueError if the value is not present.
Time complexity: O(n) where n is the length of nodes.
Args:
target: Value to look up.
Returns:
int: Index of the value.
""" item: Node
for index, item inenumerate(self):if item.value == target:return index
raise ValueError(f'{target} is not in list')defcount(self, target:object)->int:"""Counts the number of occurrences of the provided value.
Time complexity: O(n) where n is the length of the nodes.
Args:
target: Value to be counted.
Returns:
int: Number of occurrences.
""" count =0 item: Node
for item in self:if item.value == target: count +=1return count
definsert(self, index:int, value:object):"""Insert before index.
Time complexity: O(n)
Args:
index: Index to insert before.
value: Value to insert.
"""if index <0: index = self._size + index
if index > self._size -1:raise IndexError('Index out of range.')if index ==0: self._head = Node(value, self._head)else: prev_pointer = self._head
item: Node
for idx, item inenumerate(self):if idx == index: new_node = Node(value, item) prev_pointer.next= new_node
break; prev_pointer = item
self._size +=1defremove(self, value):"""Removes the first occurrence of value.
Raises ValueError if the value is not present.
Args:
value: Value to be removed.
""" common_error = ValueError('Value not found')if self._head isNone:raise common_error
if self._head.value == value: self._head = self._head.nextelse: prev_node: Optional[Node]=None item: Node
for item in self:if item.value == value: prev_node.next= item.nextif item == self._tail: self._tail = prev_node
found =Truebreak prev_node = item
ifnot found:raise common_error
self._size -=1def_sort_nodes(self, head: Node,reversed:bool=False):"""Sorts the nodes of a linked list.
Time complexity: O(n log n)
Args:
head: head node of the linked list.
reversed: True to sort in descending order, False to sort in ascending order.
Returns:
tuple: (head, tail) of the sorted linked list.
"""# If there are only 1 or 0 nodes heads that the list is already sorted.if head isNoneor head.nextisNone:return head
temp = head
slow = head
fast = head
# We need to divide the list in half.# The fast node will be the last node when the loop ends,# and the slow node will be at the middle of the list beacause# the fast node is traversing the list two steps at the once and the slow 1 at once.# temp will be the end of the first half.# slow will be the head of the second half.# fast will be the end of the second half.# Example:# head temp slow fast# [1, 2, 3, 4 , 5 , 6, 7, 8, 9]while fast isnotNoneand fast.nextisnotNone: temp = slow
slow = slow.next fast = fast.next.next# Set the end of the first half temp.next=None left_half = self._sort_nodes(head,reversed=reversed)ifisinstance(left_half,tuple): left_half = left_half[0] right_half = self._sort_nodes(slow,reversed=reversed)ifisinstance(right_half,tuple): right_half = right_half[0]# Merge sorted_temp = Node(Node) current_node = sorted_temp
while left_half isnotNoneand right_half isnotNone:if(notreversedand left_half.value < right_half.value)or(reversedand left_half.value > right_half.value): current_node.next= left_half
left_half = left_half.nextelse: current_node.next= right_half
right_half = right_half.next current_node = current_node.nextif left_half isnotNone: current_node.next= left_half
left_half = left_half.nextif right_half isnotNone: current_node.next= right_half
right_half = right_half.next tail = current_node
while tail.nextisnotNone: tail = tail.nextreturn sorted_temp.next, tail
defsort(self,reversed:bool=False):"""Sort the list in ascending order and return None.
The reverse flag can be set to sort in descending order.
Time complexity: O(n log n)
Args:
reversed: True to sort in descending order.
Returns:
None
""" self._head, self._tail = self._sort_nodes(self._head,reversed)returnNonedefsearch(self, target:object)->bool:"""Check if the provided value is in the list.
Time complexity: O(n) where n is the length of the nodes.
Args:
target: Value to be searched inside the list.
Returns:
bool: True if found. False otherwise.
"""return target in self
defiter(self):"""Allows to iterate over the list using a generator.
Time complexity: O(n)
Returns:
Iterator[Node]: Iterator over the list.
"""if self._head isnotNone: pointer = self._head
while pointer isnotNone: val = pointer
pointer = pointer.nextyield val
returnNonedefreverse(self):"""Reverses the list.
Time complexity: O(n)
Returns:
None
"""if self._head isnotNone: current_node:None= self._head
remaining_values: Optional[Node]= self._head.next# Set the head next value to None beacuse now it will be the tail current_node.next=Nonewhile remaining_values isnotNone: temp_ref = current_node
current_node: Node = remaining_values
remaining_values = current_node.next current_node.next= temp_ref
self._tail = self._head
self._head = current_node
# ==========================# Dunders# ==========================def__delitem__(self, index: Union[int,slice]):"""Deletes an item from the list.
Time complexity: O(n)
Args:
index: Index of the item to be removed.
Returns:
None
"""ifisinstance(index,slice): list_items =list(self)del list_items[index] self.clear()for item in list_items: self.append(item)else:if index > self._size -1:raise IndexError('Index out of range.')if index ==0: self._head = self._head.nextelse: prev_pointer: Optional[Node]=None item: Node
for idx, item inenumerate(self):if idx == index: prev_pointer.next= item.nextif item == self._tail: self._tail = prev_pointer
break prev_pointer = item
self._size -=1returnNonedef__setitem__(self, index: Union[int,slice], value: Union[object, Iterable]):"""Set self[key] to value.
Time complexity: O(n)
Args:
index: Index to be set.
value: Value to assign.
"""ifisinstance(index,slice):ifnotisinstance(value, Iterable):raise TypeError('can only assign an iterable')iflen(value)>0: list_items =list(self) list_items[index]= value
self.clear()for item in list_items: self.append(item)else:if index <0: index = self._size + index
if index > self._size -1:raise IndexError('list assignment index out of range')if index ==0: self._head.value = value
else: item: Node
for idx, item inenumerate(self):if idx == index: item.value = value
breakdef__add__(self, values: Iterable)->'SinglyLinkedList':"""Returns a new list with the nodes of the current list a the values or nodes of the other list.
Time complexity: O(n) where n is the length of values to add.
Returns:
SinglyLinkedList: Merged linked list.
""" new_list = self.depthcopy()for item in values: new_list.append(item)return new_list
def__iadd__(self, values: Iterable):"""Appends values to the list when using the += operator.
Time complexity: O(n) where n is the length of items to append.
Returns:
self
"""for item in values: self.append(item)return self
def__len__(self):"""Returns the size of the linked list when using the built-in function len."""return self._size
def__mul__(self, times:int):"""
Returns a new list with the items duplicated by provided factor.
Args:
times: Number of times to duplicate the list.
Returns:
SinglyLinkedList: Duplicated list.
"""if times <=0:return SinglyLinkedList() new_list = self.depthcopy()for _ inrange(times -1): new_list += self.depthcopy()return new_list
def__rmul__(self, times:int):"""
Returns a new list with the items duplicated by provided factor.
Args:
times: Number of times to duplicate the list.
Returns:
SinglyLinkedList: Duplicated list.
"""return self.__mul__(times)def__imul__(self, times:int):"""Duplicates the current list items by the provided factor and appends them to the end.
Time complexity: O(a * b) where a is the number of duplicates to add and b is the length of the list.
Args:
times: Number of times to duplicate the list.
Returns:
self
"""if times <=0: self.clear()else: base = self.depthcopy()for _ inrange(times -1): self.extend(base.depthcopy())return self
def__iter__(self)-> Iterator[Node]:"""Allows to iterate over the list using a generator.
Time complexity: O(n)
Returns:
Iterator[Node]: Iterator over the list.
"""return self.iter()def__contains__(self, target:object)->bool:"""Check if a value is in the list when using the 'in' operator.
Time complexity: O(n) where n is the length of the nodes.
""" output =False pointer = self._head
while pointer isnotNoneand pointer.value != target and pointer.nextisnotNone: pointer = pointer.nextif pointer isnotNoneand pointer.value == target:return target
return output
def__getitem__(self, index: Union[int,slice]):"""Get item with the index or slice from the linked list.
Time Complexity: O(n) where n is the length of the nodes.
Returns:
Any: Item with the index or slice.
"""ifisinstance(index,slice): items =list(self)[index] new_list = SinglyLinkedList(items)return new_list
if index > self.size -1:raise IndexError('Index out of range')if index <0: index = self._size + index
for idx, value inenumerate(self):if index == idx:return value
returnNonedef__lt__(self, other:'SinglyLinkedList')->bool:"""Check if the list is less than the other list.
Time Complexity: O(n) where n is the length of the nodes of the list with less nodes.
Args:
other (SinglyLinkedList): Other list to be compared.
Returns:
bool: True if the list is equals to the other list. False otherwise.
"""iflen(self)>=len(other):returnFalsefor self_item, other_item inzip(self, other):if self_item.value != Node._parse_other_value(other_item):returnFalsereturnTruedef__le__(self, other:'SinglyLinkedList')->bool:"""Check if the list is less than or equals to the other list.
Time Complexity: O(n) where n is the length of the nodes of the list with less nodes.
Args:
other (SinglyLinkedList): Other list to be compared.
Returns:
bool: True if the list is equals to the other list. False otherwise.
"""iflen(self)>len(other):returnFalsefor self_item, other_item inzip(self, other):if self_item.value != Node._parse_other_value(other_item):returnFalsereturnTruedef__eq__(self, other:'SinglyLinkedList')->bool:"""Check if the list is equal to the other list.
Time Complexity: O(n) where n is the length of the nodes of the list with less nodes.
Args:
other (SinglyLinkedList): Other list to be compared.
Returns:
bool: True if the list is equals to the other list. False otherwise.
"""iflen(self)!=len(other):returnFalsefor self_item, other_item inzip(self, other):if self_item.value != Node._parse_other_value(other_item):returnFalsereturnTruedef__ge__(self, other:'SinglyLinkedList')->bool:"""
Check if the list is greater or equal than the other list.
Time Complexity: O(n) where n is the length of the nodes of the list with less nodes.
Args:
other (SinglyLinkedList): Other list to be compared.
Returns:
bool: True if the list is greater or equal than the other list. False otherwise.
"""iflen(self)<len(other):returnFalsefor self_item, other_item inzip(self, other):if self_item.value != Node._parse_other_value(other_item):returnFalsereturnTruedef__gt__(self, other:'SinglyLinkedList')->bool:"""
Check if the list is greater than the other list.
Time Complexity: O(n) where n is the length of the nodes of the list with less nodes.
Args:
other (SinglyLinkedList): Other list to be compared.
Returns:
bool: True if the list is greater than the other list. False otherwise.
"""iflen(self)<=len(other):returnFalsefor self_item, other_item inzip(self, other):if self_item.value != Node._parse_other_value(other_item):returnFalsereturnTrue
Node
classNode:"""
Node class for a linked list.
"""def__init__(self, value,next=None)->None:"""
Initialize a node with a value and a next node.
Args:
value: The value of the node.
next: The next node.
""" self.value = value
self.next=nextdefcopy(self)->'Node':"""
Return a copy of the node.
Returns:
A copy of the node.
"""return Node(self.value, self.next)@staticmethoddef_parse_other_value(other):ifisinstance(other, Node):return other.value
return other
def__lt__(self, other:'Node')->bool:"""Check if the current value is less than the other value.
Args:
other: Node to be compared.
Returns:
bool: True if the current value is less than the other one. False otherwise.
"""return self.value < self._parse_other_value(other)def__le__(self, other:'Node')->bool:"""Check if the current value is less than or equals to the other value.
Args:
other: Node to be compared.
Returns:
bool: True if the current value is less than or equals to the other one. False otherwise.
"""return self.value <= self._parse_other_value(other)def__eq__(self, other:'Node')->bool:"""Check if the current value is equals to the other value.
Args:
other: Node to be compared.
Returns:
bool: True if the current value is equals to the other one. False otherwise.
"""return self.value == self._parse_other_value(other)def__ge__(self, other:'Node')->bool:"""Check if the current value is greater than or equals to the other value.
Args:
other: Node to be compared.
Returns:
bool: True if the current value is greater than or equals to the other one. False otherwise.
"""return self.value >= self._parse_other_value(other)def__ge__(self, other:'Node')->bool:"""Check if the current value is greater than the other value.
Args:
other: Node to be compared.
Returns:
bool: True if the current value is greater than the other one. False otherwise.
"""return self.value > self._parse_other_value(other)def__str__(self)->str:returnstr(self.value)
Cuando llegué al sort todo se puso raro 😅, pero después de unas horas llegué a la solución.
Realicé pruebas unitarias pero eran bastantes como para incluirlas.
Si tienen alguna sugerencia estaría cool que me la compartieran!
Muchas gracias por tu aporte.
Esta implementación de la lista enlazada (LinkedList) incluye los siguientes métodos:
len():
Devuelve la longitud de la lista.
getitem(index):
Permite acceder a los elementos de la lista mediante índices.
setitem(index, value):
Permite modificar los elementos de la lista mediante índices.
iter():
Permite iterar sobre los elementos de la lista.
contains(value):
Verifica si un valor está presente en la lista.
append(data):
Agrega un elemento al final de la lista.
insert(index, data):
Inserte un elemento en una posición específica de la lista.
remove(data):
Elimina la primera aparición de un elemento de la lista.
index(data):
Devuelve el índice de la primera aparición de un elemento en la lista.
count(data):
Cuenta la cantidad de apariciones de un elemento en la lista.
clear():
Elimina todos los elementos de la lista.
reverse():
Invierte el orden de los elementos en la lista.
copy():
Crea una copia de la lista.
extend(iterable):
Agrega los elementos de un iterable al final de la lista.
pop(index=None):
Elimina y devuelve el elemento en la posición especificada o el último elemento si no se proporciona un índice.
str():
Devuelve una representación en cadena de la lista.
Estos métodos te permitirán utilizar la lista enlazada de manera similar a una lista estándar de Python.
que buena nota, gracias
Aquí mi solución para crear uno de los métodos (Reemplazar):
def replace(self, target_item, new_data): new_node =Node(new_data) probe = self.head is_the_first_iteration =True previuos = self.headwhile probe.next!=None and probe.data!= target_item: probe = probe.nextif not is_the_first_iteration: previuos = previuos.next is_the_first_iteration =Falseif probe.data== target_item and is_the_first_iteration: new_node.next= probe.next self.head= new_node
elif probe.data== target_item: new_node.next= probe.next previuos.next= new_node
if new_node.next==None: self.tail= new_node
else:print("The target item is not in the list.")
Si tienes problemas entendiendo cómo funciona puedes checar Aquí en mi GitHub donde está el código comentado línea a línea y todos los métodos del reto creados. Saludos!
Muchas gracias por tu aporte.
Les dejo este link que da más detalle sobre los ++LinkedList++.
Mi aporte con lo aprendido y practicado
############ Interfaz Linked List ######
from linkedlist importLinkedListdef wrong_option():print('Option Not Exist')def _welcom():print('*'*50)print('############ L I N K E D L I S T ############')print('*'*50)print('What would you like to do?:')print('[I]nsert')print('[S]earch Node')print('[C]lear LinkedList')print('[G]et length of Linkedlist')if __name__=="__main__":_welcom() command =input() command = command.upper() ll =LinkedList()if command =='I':print('[1]Insert Node')print('[2]Insert List') command =int(input())if command==1:print('[1]Insert at begining')print('[2]Insert at end')print('[3]Insert any position') command =int(input())if command==1: data=input('Introduce data: ') ll.insert_at_begining(data) elif command==2: data=input('Introduce data: ') ll.insert_at_end(data) elif command==3: data=input('Introduce data: ') index=int(input('Introduce Index'))-1 ll.insert_at(index, data)else:wrong_option() elif command ==2: n=int(input('Enter number of elements : ')) list1=[input()for i inrange(0,n)] ll.insert_value_from_list(list1)else:wrong_option() elif command=='R':print('Remove by: ')print('[I]ndex')print('[D]ata') command =input().upper()if command=='I': index=int(input('Introduce Index: ')) ll.remove_index(index) elif command=='D': data=input('Introduce Data: ') ll.remove_data(data)else:wrong_option() elif command=='S':print('Search by: ')print('[I]ndex')print('[D]ata') command =input().upper()if command=='I': index=int(input('Introduce Index: ')) ll.search_index(index) elif command=='D': data=input('Introduce Data: ') ll.search_data(data)else:wrong_option() elif command=='G': ll.get_length() elif command=='C': ll.clear()else:wrong_option() ll.print()
##### Linked List funcionts #####
from node importNodeclassLinkedList: def __init__(self): self.head=None #Function that insert a Node at the beginig of a LinkedList def insert_at_begining(self, data): node=Node(data,self.head) self.head=node
#Function that insert a Node at the end of a LinkedList def insert_at_end(self, data):if self.head is None: self.head=Node(data,None)return itr =self.headwhile itr.next: itr=itr.next itr.next=Node(data,None) #Function that insert a NodeinLinkedList def insert_at(self, index, data):if index<0 or index>self.get_length(): raise Exception("Invalid Index")else: itr=self.headif index==0: self.insert_at_begining(data) elif index==self.get_length(): self.insert_at_end(data)else:while index>1 and itr.next!=None: index-=1 itr=itr.next itr.next=Node(data, itr.next) #Function that insert a Listin a LinkedList def insert_value_from_list(self, data_list): self.head=Nonefor data indata_list: self.insert_at_end(data) #Function that returns the size ofLinkedList def get_length(self): count=0 itr=self.headwhileitr: count+=1 itr=itr.nextreturn count
#Function that remove a NodeofLinkedList by it Index def remove_index(self, index):if index<0 or index>=self.get_length():return count=0 itr=self.headwhileitr:if count==index-1: itr.next=itr.next.nextbreak itr=itr.next count+=1 #Function that remove a NodeofLinkedList by Data def remove_data(self, data): itr=self.head previous=self.headwhile itr.next:if itr.data==data:if itr==self.head: self.head=itr.nextelse: previous.next=itr.nextreturn itr.data previous=itr
itr=itr.next def _iter(self): itr=self.headwhileitr: val=itr.data itr=itr.nextyield val
#Function that search a Node by Data def search_data(self, data):for node in self._iter():if data==node:print(f'Data {data} found') #Function that search a Node by Index def search_index(self ,index): #pendiente por indice
itr=self.head count=1while itr!=None and index<=self.get_length():if count==index: data=itr.dataprint(f'In the index {index} you will found the data {data}')breakelse: count+=1 itr=itr.next #Replace a node with a newone def replace(self, data, new_data): itr=self.headwhile itr !=None and itr.data!=data: itr=itr.nextif itr!=None: itr.data= new_data
print(f'The node {data} has been replaced by {new_data}')else:print(f'The target item {data} is not in the Linked List') #Clear the LinkedList def clear(self): self.head=None self.size=0 def print(self):if self.head is None:print("Linked list is empty")return itr=self.head llstr=''whileitr: llstr+=str(itr.data)+'-->' itr =itr.nextprint(llstr)
Por si a caso,
itr es la varaible iterable
Añadiendo el método iter
defiter(self): current = self.tail
while current: value = current.data
current = current.nextyield value
reto cumplido agrege a mi clase el metodo eliminar, buscar, actualizar, colocar al inicio, insertar en cualquier lugar y un ultimo crear una lista donde muestra en formato de lista como estan conectados los diferenters nodos
Pesimo curso, el anterior era muy bueno.
Por si alguien le sirve, dejo en detalle como intercambiar dos posiciones con index, con comentarios, así se tienen varios conceptos juntos.
Ejemplo:
D -> A
A -> B
B -> C
C -> E
E
my_new_list.exchange(0, 3)
C -> A
A -> B
B -> D
D -> E
E
La clase completa con los métodos anteriores:
from node importNodeclassSinglyLinkedList: def __init__(self): self.head=None self.size_list=0 def append(self, data): node =Node(data)if self.head==None: self.head= node
else: current = self.headwhile current.next: current = current.next current.next= node
self.size_list+=1 def size(self):return self.size_list def iter(self): current = self.headwhilecurrent: val = current.data current = current.nextyield val
def delete(self, data): current = self.head previous = self.headwhilecurrent:if current.data== data:if current == self.head: self.head= current.nextelse: previous.next= current.next self.size_list-=1return current.data previous = current
current = current.next def search(self, data): found =Falsefor node in self.iter():if data == node:print(f"Data {data} found!") found =Trueif not found:print(f"Data {data} not found!") def clear(self): self.head=None self.head=None self.size_list=0 # Print values in the linked list
def show(self): probe = self.headwhile probe !=None:print(probe.data) probe = probe.next # Searching a node
def search_node(self, item): probe = self.headwhile probe !=None and item != probe.data: probe = probe.nextif probe !=None:print(f"Target item {item} has been found!")else:print(f"Target item {item} is not in the linked list!") # Replace data in a node with other data
def replace_node(self, item, new_item): probe = self.headwhile probe !=None and item != probe.data: probe = probe.nextif probe !=None: probe.data= new_item
print(f"{new_item} replaced the old value {item} in the node")else:print(f"The target item {item} is not in the linked list") # Insert node at the beginning of the list
def insert_node_begin(self, data): self.head=Node(data, self.head) # Insertnewnodein the end of the list
def insert_node_ending(self, data): new_node =Node(data)if self.head is None: self.head= new_node
else: probe = self.headwhile probe.next!=None: probe = probe.next probe.next= new_node
# Delete the node at beginning of the list
def delete_node_begin(self): removed_item = self.head.data self.head= self.head.nextprint(f"The node {removed_item} was deleted") # Delete the node in the end of the list
def delete_node_end(self): removed_item = self.head.dataif self.head.next is None: self.head=Noneelse: probe = self.headwhile probe.next.next!=None: probe = probe.next removed_item = probe.next.data probe.next=Noneprint(f"The node {removed_item} was deleted") # Add node in determined position
def add_node_position(self, item, index):if self.head is None or index <0: self.head=Node("Py", self.head)else: probe = self.headwhile index >1 and probe.next!=None: probe = probe.next index -=1 probe.next=Node(item, probe.next) # Delete node in determined position
def delete_node_position(self, index):if index <=0 or self.head.next is None: removed_item = self.head.data self.head= self.head.nextprint(f"The node {removed_item} was deleted")else: probe = self.headwhile index >1 and probe.next.next!=None: probe = probe.next index -=1 removed_item = probe.next.data probe.next= probe.next.nextprint(f"The node {removed_item} was deleted ")llist =SinglyLinkedList()llist.append("A")llist.append("B")llist.append("C")llist.append("D")llist.show()# Insert node at the beginning
llist.insert_node_begin("Z")print("List with new node at the beginning")llist.show()# Search a node
llist.search_node("C")# Replace a node
llist.replace_node("B","F")print("New list")llist.show()# Insert node in the end
llist.insert_node_ending("H")print("List with new node in the end")llist.show()# Delete the node beginning of the list
llist.delete_node_begin()print("New list with node deleted at beginnining")llist.show()# Delete the node in the end of the list
llist.delete_node_end()print("New list with node deleted in the end")llist.show()# Add node in position 3llist.add_node_position("P",3)print("New list with new node added in position 3")llist.show()# Delete the node in position 1llist.delete_node_position(1)print("New list without the node in position 1 ")llist.show()
creo que llamar tail al primer valor que entra no es muy habitual, usualmente se le llama head al primera valor.
Ejemplo:
classNode:def__init__(self, data,next=None): self.data = data
self.next=NoneclassSinglyLinkedList:def__init__(self): self.head =None self.size:int=0
Mi aporte con todos los métodos:
from nodes importNodeclasssinglyLinkedList(): ##constructor
def __init__(self)->None: self.head=None self.tail=None self.size=0
## add a node at the begining
def push(self, value):"""Add a node at the begining""" new_node =Node(value)if self.head==None: self.head= new_node
else: new_node.next= self.head self.head= new_node
self.size+=1 ## add a node at the end of linked list(floating tail) def append(self, value):"""add a node at the end of linked list (floating tail)""" new_node =Node(value)if self.head==None: self.head= new_node
else: current = self.headwhile current.next: current = current.next current.next= new_node
self.size+=1 ## delete first node of list
def deleteFirst(self):"""delete first node of list""" current = self.headif self.head==None:print('The list is empty!')else: self.head= current.next self.size-=1 ## delete laste node of list
def deleteLast(self):"""delete first node of list""" current = self.headif self.head==None:print('The list is empty!')else:whilecurrent:if current.next.next==None: current.next=None current = current.next self.size-=1
## insert node at specified position
def insert(self, value, position=int):"""insert node at specified position (equals index like using array.insert())""" current = self.head pos =0if position > self.size:print('Position out of list size!')else:whilecurrent:if position == pos +1: current.next=Node(value, current.next)break current = current.next pos +=1 self.size+=1 ## delete node at specified position
def delete(self, position):"""delete node at specified position (equals index like using array.remove()). Not valid for first or last position (use deleteFirst or deleteLast instead)""" current = self.head pos =0if position > self.size-1 or position <=0:print('Position not valid! Use deleteFirst or deleteLast instead')else:whilecurrent:if position == pos +1: current.next= current.next.nextbreak current = current.next pos +=1 self.size-=1 def size(self):returnstr(self.size) def printList(self): current = self.headprint('Data in Single Linked List:', end='\n')while current is not None:print(current.data, end=" ") current = current.nextprint('') def iter(self): current = self.headwhilecurrent: val = current.data current = current.nextyield val
if __name__ =='__main__': linkedList =singlyLinkedList()for i inrange(6,0,-1): linkedList.push(i)for i inrange(7,11): linkedList.append(i) linkedList.printList() linkedList.deleteFirst() linkedList.deleteLast() linkedList.insert(17,3) linkedList.delete(3) linkedList.printList()
ejecute todas la operaciones de forma mas pythonista XD
classNodo: def __init__(self, valor, siguiente_nodo =None): self.valor= valor
self.siguiente_nodo= siguiente_nodo
classLista_nodo: def __init__(self): self.limpiar() def limpiar(self): self.nodo_actual=None self.__SEGURO__=False self.nodo_tmp=None self.tam=0
@staticmethod
def a_lista_nodo(data): nueva_lista =Lista_nodo()iftype(data)== list or type(data)== tuple:for val indata:Lista_nodo.append(val) elif type(data)== dict:forK,Vin data.items(): nueva_lista.append((K,V)) elif type(data)==Nodo: nueva_lista.nodo_actual= data
nueva_lista.tam=1while data.siguiente_nodo: nueva_lista.tam+=1 data = data.siguiente_nodo elif type(data)== str:for val in data.split(" "): nueva_lista.append(val)else: nueva_lista.append(data)return nueva_lista
def add(self, struct, indice =-1):Lista_nodo_2= struct
iftype(struct)!=Lista_nodo:Lista_nodo_2=Lista_nodo.a_lista_nodo(struct)if self.tam==0: self =Lista_nodo_2return elif Lista_nodo_2.tam==0:return self.tam+=Lista_nodo_2.tamLista_nodo_2.__SEGURO__=True tmp_2 =Lista_nodo_2.index(-1)Lista_nodo_2.__SEGURO__=Falseif indice ==0: tmp_2.siguiente_nodo= self.nodo_actual self.nodo_actual=Lista_nodo_2.nodo_actualreturntry: self.__SEGURO__=True tmp = self.index(indice) except AssertionError: raise AssertionError("Indice inexistente")finally: self.__SEGURO__=False self.nodo_tmp.siguiente_nodo=Lista_nodo_2.nodo_actual tmp_2.siguiente_nodo= tmp
def append(self,valor): nodo_nuevo =Nodo(valor) self.tam+=1if not self.nodo_actual: self.nodo_actual= nodo_nuevo
return nodo_siguiente = self.nodo_actualwhile nodo_siguiente.siguiente_nodo: nodo_siguiente = nodo_siguiente.siguiente_nodo nodo_siguiente.siguiente_nodo= nodo_nuevo
def index(self,indice):if not self.tam: raise AssertionError("Error sin elementos") def INDEX(INDICE):ifINDICE> self.tam-1 or INDICE<0: raise AssertionError("Error de indice fuera de los limites") i =0 self.nodo_tmp= nodo = self.nodo_actualwhile i !=INDICE and nodo.siguiente_nodo: self.nodo_tmp= nodo
nodo = nodo.siguiente_nodo i +=1if self.__SEGURO__:return nodo
return self.nodo_tmp.siguiente_nodo.valorif indice <0:returnINDEX(self.tam+ indice)else:returnINDEX(indice) def pop(self,indice =-1): self.__SEGURO__=Truetry: self.nodo_tmp.siguiente_nodo= self.index(indice).siguiente_nodo self.tam-=1 except AssertionError: raise AssertionError("Indice inexistente")finally: self.__SEGURO__=False def find(self,valor):for val , indice in self.iter_items():if val == valor:print("valor encontrado")return indice
print("el valor no existe")returnNone def printing(self,elementos_mostrados_en_fila =10):print("|",end="") salto = elementos_mostrados_en_fila -1for val, i in self.iter_items():if i < salto:print(f" {val} |",end="")else: salto += elementos_mostrados_en_fila -1print(f" {val} |")print("") def iter(self):for val, i in self.iter_items():yield val
def iter_items(self): nodo_siguiente = self.nodo_actualif not nodo_siguiente:return i =0while nodo_siguiente.siguiente_nodo: val = nodo_siguiente.valor nodo_siguiente = nodo_siguiente.siguiente_nodoyield(val, i) i +=1yield(nodo_siguiente.valor,i)if __name__ =="__main__":from random import randint
lista =Lista_nodo()print("\nmetodo append [ Nodo.append(",end="")for i inrange(1,8): val =randint(1,20)print(f"{val},",end="") lista.append(val)print(") ]\n")print("metodo pop [Nodo.pop(\"con o si indice\")]\n") lista.printing() i =4 lista.pop(i)print(f"Nodo.pop({i})") lista.printing()print("\nmetodo index [Nodo.index(int)]\n")print(f"Nodo[{i}] = {lista.index(i)}")print("\nmetodo iter [Nodo.iter()]\n")for val in lista.iter():print(val,end=",")print("\n\nmetodo iter_items [Nodo.iter_items()]\n")for val, idx in lista.iter_items():print(f"[{idx}] = {val}",end=" | ")print("\n\nmetodo find [Nodo.find(\"valor\")]\n") j =11print(f"indice = {lista.find(j)} Nodo.find({j})\n") string ="hola adios" nodo =Nodo("uno")print(f"\nmetodo add Node.add(data,posicion)\n") lista.printing(15) lista.add(string,4)print(f"Node.add(str, 4) str = {string}") lista.printing(15) lista.add(nodo,0)print(f"Node.add(nodo, 0) nodo simple = {nodo.valor}") lista.printing(15) dicionario ={"one":1,"two":2,"three":3} lista.add(dicionario,-2)print(f"Node.add(dicionario, 0) nodo simple = {dicionario}") lista.printing(15) nueva_lista =Lista_nodo()for i inrange(1,5): val =randint(87,126) nueva_lista.append(chr(val))print(f"Node.add(lista_nodos, 3) otra lista de nodos = ",end="") nueva_lista.printing() lista.add(nueva_lista,3) lista.printing(15)
Aquí mi solución con todos los métodos:
Les comparto la clase que cree usando las operaciones presentadas en el video.
Decidi que el head sería el index 0.
from node importNodeclassSimpleLinkedList(): def __init__(self): self.head=None def range(self, start, stop): # *Creación de los nodos enlazados(linked list)for count inrange(stop, start,-1): self.head=Node(count, self.head) def __str__(self): # *Recorrer e imprimir valores de la lista
probe = self.head result =''while probe !=None: result += f'{probe.data} ' probe = probe.next result = result.strip()return result
def search(self, target_item): # *Busqueda de un elemento
probe = self.headwhile probe !=None and target_item != probe.data: probe = probe.nextif probe !=None:print(f'Target item {target_item} has been found')return probe
else:print(f'Target item {target_item} is not in the linked list')return-1 def replace(self, target_item, new_item): # *Remplazo de un elemento
probe = self.headwhile probe !=None and target_item != probe.data: probe = probe.nextif probe !=None: probe.data= new_item
print( f"{new_item} replace the old value in the node number {target_item}")else:print(f"The target item {target_item} is not in the linked list") def unshift(self, new_item): # *Insertar un nuevo elemento/nodo al inicio(head) self.head=Node(new_item, self.head) def append(self, new_item): # *Insertar un nuevo elemento/nodo al final(tail) new_node =Node(new_item)if self.head is None: self.head= new_node
else: probe = self.headwhile probe.next!=None: probe = probe.next probe.next= new_node
def shift(self): # *Eliminar un elmento/nodo al inicio(head) removed_item = self.head.data self.head= self.head.nextprint(f'Removed_item: {removed_item}')return removed_item
def pop(self): # *Eliminar un elmento/nodo al final(tail) removed_item = self.head.dataif self.head.next is None: self.head=Noneelse: probe = self.headwhile probe.next.next!=None: probe = probe.next removed_item = probe.next.data probe.next=Noneprint(f'Removed_item: {removed_item}')return removed_item
def insert(self,new_item,index): # *Agregar un nuevo elemento/nodo por "indice"(Cuenta de Head-Tail)if self.head is None or index <=0: self.head=Node(new_item, self.head)else: probe = self.headwhile index >1 and probe.next!=None: probe = probe.next index -=1 probe.next=Node(new_item, probe.next) def delete_by_index(self,index): # *Eliminar un nuevo elemento/nodo por "indice"(Cuenta de Head-Tail)if self.head is None or index <=0: removed_item = self.head.data self.head= self.head.nextprint(removed_item)else: probe = self.headwhile index >1 and probe.next.next!=None: probe = probe.next index -=1 removed_item = probe.next.data probe.next= probe.next.nextprint(f'Removed_item: {removed_item}')return removed_item
En este código pruevo el funcionamiento
from simple_linked_list importSimpleLinkedListsimple_list =SimpleLinkedList()simple_list.range(0,6)print(simple_list)simple_list.search(2)simple_list.search(-1)simple_list.replace(3,'replace')print(simple_list)simple_list.unshift('shift')print(simple_list)simple_list.append('apppend')print(simple_list)simple_list.shift()print(simple_list)simple_list.pop()print(simple_list)simple_list.insert("insert",3)print(simple_list)simple_list.delete_by_index(3)print(simple_list)
y las salidas
123456Target item 2 has been found
Target item -1 is not in the linked list
replace replace the old value in the node number 312 replace 456shift 12 replace 456shift 12 replace 456 apppend
Removed_item: shift
12 replace 456 apppend
Removed_item: apppend
12 replace 45612 replace insert 456Removed_item: insert
12 replace 456