En este módulo, exploraremos estructuras de datos avanzadas en Python que son esenciales para resolver problemas complejos de manera eficiente. Estas estructuras de datos incluyen listas enlazadas, pilas, colas, árboles y grafos. Aprenderemos cómo implementarlas y utilizarlas en Python.
Contenido
- Listas Enlazadas
- Pilas
- Colas
- Árboles
- Grafos
- Listas Enlazadas
Concepto
Una lista enlazada es una colección de nodos donde cada nodo contiene un valor y una referencia al siguiente nodo en la secuencia. A diferencia de las listas en Python, las listas enlazadas no almacenan sus elementos en ubicaciones contiguas en memoria.
Implementación en Python
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
last_node = self.head
while last_node.next:
last_node = last_node.next
last_node.next = new_node
def print_list(self):
current_node = self.head
while current_node:
print(current_node.data, end=" -> ")
current_node = current_node.next
print("None")
# Ejemplo de uso
ll = LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.print_list()Explicación
- Node: Clase que representa un nodo en la lista enlazada.
- LinkedList: Clase que maneja la lista enlazada.
- append: Método para agregar un nodo al final de la lista.
- print_list: Método para imprimir los elementos de la lista.
Ejercicio
Implementa un método insert_at_position en la clase LinkedList que inserte un nodo en una posición específica.
def insert_at_position(self, data, position):
new_node = Node(data)
if position == 0:
new_node.next = self.head
self.head = new_node
return
current_node = self.head
for _ in range(position - 1):
if not current_node:
raise IndexError("Position out of bounds")
current_node = current_node.next
new_node.next = current_node.next
current_node.next = new_node
- Pilas
Concepto
Una pila es una estructura de datos que sigue el principio LIFO (Last In, First Out). Los elementos se agregan y se eliminan desde el mismo extremo, conocido como el "tope" de la pila.
Implementación en Python
class Stack:
def __init__(self):
self.stack = []
def push(self, data):
self.stack.append(data)
def pop(self):
if not self.is_empty():
return self.stack.pop()
return "Stack is empty"
def peek(self):
if not self.is_empty():
return self.stack[-1]
return "Stack is empty"
def is_empty(self):
return len(self.stack) == 0
# Ejemplo de uso
s = Stack()
s.push(1)
s.push(2)
s.push(3)
print(s.pop()) # 3
print(s.peek()) # 2Explicación
- Stack: Clase que representa una pila.
- push: Método para agregar un elemento a la pila.
- pop: Método para eliminar y devolver el elemento del tope de la pila.
- peek: Método para devolver el elemento del tope sin eliminarlo.
- is_empty: Método para verificar si la pila está vacía.
Ejercicio
Implementa un método size en la clase Stack que devuelva el número de elementos en la pila.
- Colas
Concepto
Una cola es una estructura de datos que sigue el principio FIFO (First In, First Out). Los elementos se agregan en un extremo (final) y se eliminan desde el otro extremo (frente).
Implementación en Python
class Queue:
def __init__(self):
self.queue = []
def enqueue(self, data):
self.queue.append(data)
def dequeue(self):
if not self.is_empty():
return self.queue.pop(0)
return "Queue is empty"
def peek(self):
if not self.is_empty():
return self.queue[0]
return "Queue is empty"
def is_empty(self):
return len(self.queue) == 0
# Ejemplo de uso
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
print(q.dequeue()) # 1
print(q.peek()) # 2Explicación
- Queue: Clase que representa una cola.
- enqueue: Método para agregar un elemento al final de la cola.
- dequeue: Método para eliminar y devolver el elemento del frente de la cola.
- peek: Método para devolver el elemento del frente sin eliminarlo.
- is_empty: Método para verificar si la cola está vacía.
Ejercicio
Implementa un método size en la clase Queue que devuelva el número de elementos en la cola.
- Árboles
Concepto
Un árbol es una estructura de datos jerárquica que consiste en nodos, donde cada nodo tiene un valor y referencias a sus nodos hijos. El nodo superior se llama raíz.
Implementación en Python
class TreeNode:
def __init__(self, data):
self.data = data
self.children = []
self.parent = None
def add_child(self, child):
child.parent = self
self.children.append(child)
def get_level(self):
level = 0
p = self.parent
while p:
level += 1
p = p.parent
return level
def print_tree(self):
spaces = ' ' * self.get_level() * 3
prefix = spaces + "|__" if self.parent else ""
print(prefix + self.data)
if self.children:
for child in self.children:
child.print_tree()
# Ejemplo de uso
root = TreeNode("Electronics")
laptop = TreeNode("Laptop")
laptop.add_child(TreeNode("Mac"))
laptop.add_child(TreeNode("Surface"))
laptop.add_child(TreeNode("Thinkpad"))
root.add_child(laptop)
root.print_tree()Explicación
- TreeNode: Clase que representa un nodo en el árbol.
- add_child: Método para agregar un nodo hijo.
- get_level: Método para obtener el nivel del nodo en el árbol.
- print_tree: Método para imprimir el árbol.
Ejercicio
Implementa un método find en la clase TreeNode que busque un nodo por su valor y devuelva el nodo si se encuentra.
def find(self, data):
if self.data == data:
return self
for child in self.children:
result = child.find(data)
if result:
return result
return None
- Grafos
Concepto
Un grafo es una estructura de datos que consiste en un conjunto de nodos (o vértices) y un conjunto de aristas que conectan pares de nodos. Los grafos pueden ser dirigidos o no dirigidos.
Implementación en Python
class Graph:
def __init__(self):
self.graph = {}
def add_vertex(self, vertex):
if vertex not in self.graph:
self.graph[vertex] = []
def add_edge(self, vertex1, vertex2):
if vertex1 in self.graph and vertex2 in self.graph:
self.graph[vertex1].append(vertex2)
self.graph[vertex2].append(vertex1) # Para grafos no dirigidos
def print_graph(self):
for vertex in self.graph:
print(f"{vertex} -> {', '.join(self.graph[vertex])}")
# Ejemplo de uso
g = Graph()
g.add_vertex("A")
g.add_vertex("B")
g.add_vertex("C")
g.add_edge("A", "B")
g.add_edge("A", "C")
g.print_graph()Explicación
- Graph: Clase que representa un grafo.
- add_vertex: Método para agregar un vértice al grafo.
- add_edge: Método para agregar una arista entre dos vértices.
- print_graph: Método para imprimir el grafo.
Ejercicio
Implementa un método find_path en la clase Graph que encuentre un camino entre dos vértices utilizando búsqueda en profundidad (DFS).
def find_path(self, start_vertex, end_vertex, path=[]):
path = path + [start_vertex]
if start_vertex == end_vertex:
return path
if start_vertex not in self.graph:
return None
for vertex in self.graph[start_vertex]:
if vertex not in path:
extended_path = self.find_path(vertex, end_vertex, path)
if extended_path:
return extended_path
return NoneConclusión
En esta sección, hemos cubierto varias estructuras de datos avanzadas, incluyendo listas enlazadas, pilas, colas, árboles y grafos. Estas estructuras son fundamentales para resolver problemas complejos de manera eficiente. Asegúrate de practicar implementando y utilizando estas estructuras para fortalecer tu comprensión y habilidades en programación.
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones de Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
Módulo 8: Temas Avanzados
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn
