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()) # 2
Explicació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()) # 2
Explicació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 None
Conclusió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