Alejandro Giraldo Londoño
Yorlys Oropeza
Excelente Aporte :thumbsup:
Ariel Jorge Viniegra Riveros
Mil gracias, la verdad no entendí en su totalidad la clase del profesor, pero tu artículo me ayudó a entender mas.
¿Qué son los nodos y cómo se utilizan en estructuras de datos más complejas?
Los nodos son componentes fundamentales para la creación de estructuras de datos complejas y más elaboradas. Cada nodo almacena un valor o dato y contiene un puntero que dirige hacia otro nodo. Este tipo de estructura es invaluable cuando se maneja información dispersa en memoria y las limitaciones de espacio impiden disponer los datos de forma continua. Vamos a examinar cómo se crean y utilizan nodos en programación.
¿Cómo crear una clase nodo en Python?
Comencemos creando una clase llamada Node. La definición de la clase incluye un constructor __init__ con atributos clave: data y next. El atributo data almacenará el valor del nodo, y next indicará a qué nodo apunta, con un valor predeterminado de None para el último nodo.
class Node: def __init__(self, data, next=None): self.data = data self.next = next
¿Cómo instanciar y enlazar nodos?
Una vez definida la clase, podemos instanciar nodos e interconectarlos. Veamos un ejemplo de cómo funciona esto:
Creamos varios nodos:
node1 sin valor inicial (None).node2 con un valor de dato 'a' que no apunta a otro nodo.node3 con un valor de dato 'b' que apunta al node2.Para visualizar los datos o las referencias de un nodo, empleamos sus atributos.
node1 = Node(None) node2 = Node('a') node3 = Node('b', node2) # Mostrar datos y referencias print(node2.data) # Output: a print(node2.next) # Output: None print(node3.next.data) # Output: a
¿Cómo modificar las referencias de los nodos?
Podemos modificar las referencias de un nodo para que apunten a otros nodos. Esto es útil cuando deseamos reorganizar la estructura de datos.
node1.next = Node('c', node3) print(node1.next.data) # Output: b print(node1.data) # Output: c
¿Cómo crear una serie de nodos usando un ciclo?
Una práctica común es usar bucles para generar una serie secuencial de nodos. Veamos cómo crear una lista de nodos con un ciclo for:
head = None for count in range(1, 5): head = Node(count, head) current = head while current: print(current.data) current = current.next
Esta estructura recorrerá nodos desde el final al primero, mostrando los números en orden inverso.
¿Cuáles son las ventajas de usar nodos?
Por supuesto, dominar los nodos y las series conectadas como Linked lists enriquece tu capacidad para manejar datos de manera eficiente y eficaz. Experimentar con ciclos, iteraciones y referencias ofrece una gran profundidad en el manejo de estructuras complejas. Continúa explorando y aplicando estas técnicas: el entendimiento y facilidad para trabajar con nodos solo mejorará con la práctica.
Alejandro Giraldo Londoño
Yorlys Oropeza
Excelente Aporte :thumbsup:
Ariel Jorge Viniegra Riveros
Mil gracias, la verdad no entendí en su totalidad la clase del profesor, pero tu artículo me ayudó a entender mas.
Mario Andrés Castro Martínez
Una forma mas clara de ver la composicion de los nodos es usando dataclasses, que son una forma un poco mas sencilla de declarar clases en Python : Data Classes in Python 3.7+ (Guide)
++Clase Node++:
++Main++:
++Output++:
Mauricio Gonzalez Falcon
Gracias!
Hector Saldaña Espinoza
Wooow excelente manera de ver los nodos con las dataclasses
Christian Molina Vázquez
Pienso que el for debio haber sido for count in range(1,6) para que coincida con la deapositiva de crear 5 nodos. Recuerden que en la función range, el segundo valor es exclusivo, por lo que no es agregado.
Aún me parece extraño que aunque se sobreescriba la variable head para crear otro nodo, esta siga guardando la referencia en memoria del anterior nodo creado.
Jheyshon Michel Vilchez Canchucaja
Si te refieres a esta parte head = Node(count, head) se podría ver de esta manera i = i + 1 (primero incrementa luego lo sobreescribe) en este caso crea un nuevo nodo con el head del ciclo anterior luego lo sobreescribe (nuevo nodo). Y bueno para el while el head de inicio vendría a ser el nodo creado en el ultimo ciclo.
Alexis Dorado Muñoz
Gracias por tu aporte.
Ramsés Alejandro Camas Nájera
De esta manera dejé mi clase de Nodo con tipado estático para que fuese más claro.
from __future__ import annotations from typing import Any class Node(): def __init__(self, data:Any, next: Node = None) -> None: self.data = data self.next = next
Alexis Dorado Muñoz
Gracias por tu aporte.
Nicolás Moreno
Que lastima que un tema tan interesante esté dictado de una manera tan confusa. Para entender este curso me tocó estudiar por mi cuenta en otras páginas por meses y aún así se hace difícil de seguir el proceso lógico que sigue el docente. Ojalá lo renueven con otro docente, todos los cursos que he visto de Héctor Vega son igual de malos en cuanto a pedagogía.
Juan Manuel Martínez
Estoy de acuerdo. No reconoce que nosotros no tenemos el dominio de él en ciertas instrucciones computacionales, como lo recursivo, que cuesta tiempo madurarlo... si evitara esa recursividad, o al menos no usara dos instrucciones recursivas de un plumazo, daría una confusión menor. En el primer for asigna al head.next el valor de head: al head recién creado, la asigna el valor del head pasado. ¿por qué? porque primero opera la definición del node, a la derecha del paréntesis, donde 'head' es el nodo de la iteración anterior, y luego asigna al 'head' nombre head el nuevo nodo. Más fácil decir Node0 = Node Node1 = Node(1,Node0) Nodo2 = Node(2,Node1)... como al final del for terminamos con head asignado al node con data = 4, el while parte del nodo4, recorriendo hacia atrás hasta llegar a null
Germán García
que triste que dejen estos cursos así tan bien que iba con fundamentos, y comprenhentios errores funciones de Matías
Santiago Ortiz Ceballos
Siendo un poco explícito, hicimos algo así:
Germán García
Eduardo Delgado Agudelo
Sobre todo en el video anterior y al comienzo de este siento que me distrae mucho, mientras explica datos importantes, cuando mira hacia arriba o a su derecha (si es un telepronter o la pantalla) genial que a futuro actualicen estas clases que están muy interesantes ubicando la pantalla justo en frente o de algún ángulo que no se note tanto el cambio de vista. Gracias.
Germán García
increíble que nunca se equivoca, como si lo estuviera copiando jejeje
Escribi este codigo para imprimir las conexiones entre nodos
from node import Node head = None for letter in "ABCDEFG": head = Node(letter, head) while head != None: print(f"{head.data} -> {head.next.data if head.next else None}") head = head.next
Esto imprime
G -> F F -> E E -> D D -> C C -> B B -> A A -> None
Javier Marin Ayza
Una pregunta.... esto aprendía en su momento a realizarlo en C, claro, los argumentos eran claramente diferenciados porque uno era una variable (un dato) y el otro era un puntero ( una dirección de memoria ) por lo que quedaba más claro, desde mi punto de vista... Aquí los dos argumentos son variables, esto porque es? porque en python siempre se pasa valores por referencia?
David Rangel
Marta Maleyka Magallón Escobar
class Nodo: def __init__(self, valor): self.valor = valor self.izquierda = None self.derecha = None # Crear nodos nodo1 = Nodo(1) nodo2 = Nodo(2) nodo3 = Nodo(3) # Establecer relaciones entre nodos nodo1.izquierda = nodo2 nodo1.derecha = nodo3
ROBERT ORLANDO TORO MARQUINA
Aporte de la clase
class Node(): def __init__(self, data, next=None): """Initialize this node with the given data.""" self.data = data self.next = next if __name__ == "__main__": node1 = None node2 = Node("A", None) node3 = Node("B", node2) node1 = Node("C", node3) print(f'Impresion de ref memoria del nodo2: {node2}') print(f'Impresion de la data del nodo2: {node2.data}') print(f'Impresion siguiente de ref memoria nodo3,es decir ref memoria nodo2: {node3.next}') print(f'Impresion de la data siguiente del nodo3,es decir nodo2:{node3.next.data}') head = None #se define head con valores vacios print("\n\n") for count in range(1, 5): head = Node(count, head) #Como datos se ingresa, la cuenta de bucle y apunta al siguiente valor de la cuenta while head != None: #Como head ya no esta vacio por el bucle for anterior se ejecuta print(head.data) #Se imprime la data cada valor de head head = head.next #Y se apunta al siguiente valor
Germán García
No estoy entendiando ni papas
Germán García
youtube_com/watch?v=qk67wS7WYxo
con esté video lo entendí mejor y eso que los explica con JS y no se nada de JS
Mario Alexander Vargas Celis
class Node(): def __init__(self, data, next = 0): self.data = data self.next = next
Jhon Freddy Tavera Blandon
class Node: def __init__(self, data): self.data = data self.next = None # Crear nodos individuales nodo1 = Node(1) nodo2 = Node(2) nodo3 = Node(3)
Recuerda que en una lista enlazada, los nodos se enlazan estableciendo la referencia next del nodo actual para que apunte al siguiente nodo en la secuencia. En este ejemplo, los nodos aún no están enlazados. Si deseas enlazarlos para formar una lista enlazada, necesitarás establecer las referencias next adecuadamente.
Nicolas Alpargatero
Al hacer la práctica se entendió mejor, la evolución de como el código llega hasta allá y por qué. Gracias también a los compañeros por sus buenos aportes, que sería de platzi sin la comunidad.
Mariano Gobea Alcoba
Juan Manuel Martínez
Para el profesor las formulas recursivas están internalizadas (es ‘recurrente’ en utilizarlas) y jura que nosotros también somos igual que él. Intentaré un código que le quita un grado de recursividad y con eso se hace más compresible (al menos para mí)
reemplazo al for por:
Nodo0 = None Nodo1 = Node(1,Nodo0) Nodo2 = Node(2,Nodo1) Nodo3 = Node(3,Nodo2) Nodo4 = Node(4,Nodo3)
y luego opero el while de esta forma:
NodoActual = Nodo4 while NodoActual != None: print(NodoActual.data) NodoActual = NodoActual.next
Al menos a mí me ayudó… “NodoActual = NodoActual.next” opera primero obteniendo el Nodo next a la derecha del paréntesis (el Nodo4.next→ Nodo3), y luego reasignando el valor NodoActual al nodo recién referenciado (Nodo3)… de la misma forma en que al ejecutar “i = i - 1”, se reduce el valor actual de i, como instrucción a la derecha del =, y luego de reasigna el valor de i.
David Rosas
head, cuyo valor asignado quedo el numero 4 (al cual podemos acceder directamente con head.data como en el ejemplo anterior).
3, y al cual podemos acceder con head.next con lo que nos arrojara de hecho su valor en memoria.head, necesitando para acceder, por ejemplo, a su valor el comando head.next.data.head? Lo que me da tranquilidad de que existen por separado, es que en realidad si podemos ver que si tienen un valor en memoria diferente y lo podemos ver imprimiendo, por ejemplo, en el ciclo while, en vez de print(head.data), escribir simplemente print(head):while head != None: print(head) head = head.next
dando como resultado, en mi caso:
# <node.Node object at 0x7fa93eae6410> # <node.Node object at 0x7fa93eae4280> # <node.Node object at 0x7fa93eae40d0> # <node.Node object at 0x7fa93eae4310>
Resumen: ■■■■■■■
Crear Nodos.
Cada nodo almacenará un valor y cada nodo tiene un puntero que llevará a otro nodo con otro valor y así obtener los datos allí almacenados. Es muy útil al tener infromación dispersa en memoria y cuando queremos que sean consultas ágiles, es importante entender que los nodos son la base para implementaciones más elaboradas de estructuras de datos, Stacks, Qeues, Deque, Doubly, Singly List, Circular list, Graphs .
Cada estructura de datos servirá para un propósito dentro de un contexto, por ejemplo los grafos acíclicos, donde se usan para sistemas de recomendaciones al mostrar las relaciones entre objetos o representar los tipos de redes que se forman entre nodos. Para crear un nodo:
NodeEste script tiene como propósito crear nodos.
Constructor:
class Node(): def __init__(self, data, _next=None): # Atributos self.data = data self.next = _next
A continuación la instancia de la clase Node
from node import Node node1 = None node2 = Node("A", None) # Los nodos al ser secuanciales permiten refrencias a cualquier lugar. node3 = Node("B", node2) def show_relations(): ''' Este script perfectamente puede ser una función que recibe al nodo como parámetro pythony llamo para mostrar las relaciones. ''' print("Esto es la ubicación en memoria de los nodos") print(node2) #<node.Node object at 0x0000022017FEAD30> print(node3) #<node.Node object at 0x0000022017FEAD90> print("Esto es el dato y muestra la relación entre nodos") print(node2.data,"-->", node2.next) #A --> None print(node3.data,"-->", node3.next) #B --> <node.Node object at 0x0000015356D6AD30> print("El siguiente dato del nodo es:") # Se refiere al nodo que está conectado y luego al dato que este contiene. print(node3.next.data) #'A' print("Creando el nodo1 y mostrando datos y relacion con nodo3 obtenemos: ") # Asignar una propiedad a un elemento para volverlo nodo. # Al intanciar la clase con una relación estamos ligando los nodos. node1= Node("C", node3) print(node1.data,"-->", node1.next)#C --> <node.Node object at 0x0000022017FEAD90> def create_nodes(): print("Creo nodos que se asignan a un solo valor en memoria, en este caso a node2: ") for node in range(5): #n --> <node.Node object at 0x000001B2AD991FD0> head = Node(node, node2) print(head.data,"-->", head.next) def run(): show_relations() create_nodes() if __name__ == '__main__': run()
#from node import Node class Node(): def __init__(self, data, next=None): self.data = data self.next = next node1 = None node2 = Node("A", None) node3 = Node("B", node2) node1 = Node("C", node3) head = None print(node2) # <__main__.Node object at 0x7fc842dd6e90> print(node2.data) # A print(node2.next) # None print(node3.next) # <__main__.Node object at 0x7f241fc96e90> print(node3.next.data) # A print(node1.next) # AttributeError: 'NoneType' object has no attribute 'next' print(node1.next.data) # B <= porque pusimos en la linea 14 que ahora el node1 apunta a node3 print(node1.data) # C for count in range(1,5): head = Node(count, head) while head != None: print(head.data) head = head.next #4 #3 #2 #1 # aqui creo que es donde se cumple lo de n-1
Les comparto mi código, deseo que les sea de utilidad:
class Node(): def __init__(self, data, next=None): # hacemos referencia None, porque el ultimo nodo te va a llevar a None self.data = data self.next = next if __name__ == '__main__': from node import Node node_1 = None node_2 = Node('A', None) node_3 = Node('B', node_2) print(node_2) print(node_2.data) print(node_2.next) print(node_3.next) # para ver el dato del siguiente nodo print(node_3.next.data) # para que el nodo_1 sin valor, lo apuntaramos a otro lado o quisieramos saber a donde apunta node_1 = Node('C', node_3) print(node_1.next.data) # B print(node_1.data) # C # asi podemos ver como utilizamos esos nodos # vamos a crear una serie de nodos head = None print('Esta es la nueva linked list') for count in range(1, 5): head = Node(count, head) print(head.data) print(head) ''' Esta es la nueva linked list 1 <node.Node object at 0x7f850db67be0> 2 <node.Node object at 0x7f850db67b50> 3 <node.Node object at 0x7f850db67af0> 4 <node.Node object at 0x7f850db67a60> ''' ''' print('aqui empieza una iteracion') while head != None: print(head.data) head = head.next ''' ''' 4 3 2 1 '''
Por si no se entendió lo que está sucediendo... Al inicializar cada nodo dentro de la misma variable, pero hacer referencia en el atributo "next" a la anterior, es como si estuviesemos cargando un nodo dentro del otro al estilo "Mamushka rusa". En una sola variable del tipo Node tenemos en realidad 4 nodos juntos. Una vez que recorremos mediante el metodo next cada uno de esos nodos la variable se "vacia" y vuelve a ser del tipo "None" como era al principio.
Les dejo el codigo con todo el último ejemplo del profe pero mas explicado y con output incluido dentro del mismo para mayor detalle. Cualquier duda a disposición:
from node import Node head = None print("Antes del for: ") print(f"head es de tipo: {type(head)}") # Estoy metiendo un nodo adentro del otro. Es fantastico... Todos quedan guardados dentro de head: for count in range(1,5): head = Node(count, head) print("Despues del for pero antes del while: ") print(f"head es de tipo: {type(head)}") # Imprimo todos los nodos anidados uno dentro del otro: while head != None: print(f"head.data: {head.data}") print(f"head.next: {head.next}") try: print(f"head.next.data: {head.next.data}") except AttributeError as error: print(error) head = head.next # Al recorrer el while hasta el None vacío mi nodo y deja de ser una variable tipo nodo para ser nuevamente una variable tipo None print("Despues del while: ") print(f"head es de tipo: {type(head)}") """ Output: 22:21:24 👽 with 🤖 mgobea 🐶 in develop/python/data_structs_python … ➜ python3 nodos_2.py Antes del for: head es de tipo: <class 'NoneType'> Despues del for pero antes del while: head es de tipo: <class 'node.Node'> head.data: 4 head.next: <node.Node object at 0x7f4135e40640> head.next.data: 3 head.data: 3 head.next: <node.Node object at 0x7f4135e40490> head.next.data: 2 head.data: 2 head.next: <node.Node object at 0x7f4135e406d0> head.next.data: 1 head.data: 1 head.next: None 'NoneType' object has no attribute 'data' Despues del while: head es de tipo: <class 'NoneType'> """