Emmanuel Guerra Sánchez
Germán García
¿Qué son las colas y cómo funcionan?
Las estructuras de datos juegan un papel fundamental en la programación, y uno de los tipos más comunes es la cola, o queue en inglés. Imagina estar en una fila en el supermercado o esperando para abordar un avión; estas experiencias cotidianas son ejemplos de cómo funcionan las colas en la programación. En las colas, se sigue el principio del FIFO (First In, First Out), es decir, el primero que entra es el primero que sale. Vamos a explorar cómo funcionan y sus variantes.
¿Cómo se organizan las colas?
FIFO (First In, First Out): Cada elemento que entra en la cola sale en el mismo orden en que llegó. Esto se ve con el ejemplo del supermercado, donde el primer cliente en llegar es el primero en ser atendido.
Rear y Front:
front es procesado, el siguiente en la fila se convierte en el nuevo front.¿Qué son las colas de prioridad?
Además de las colas tradicionales, existen las Priority Queues que permiten asignar prioridades a los elementos dentro de la cola. Esto significa que, aunque se siga un orden FIFO, ciertos elementos pueden ser atendidos antes si tienen una prioridad más alta.
Ejemplos de colas de prioridad incluyen:
¿Cuáles son los métodos comunes de las colas?
Las colas tienen varios métodos que permiten su gestión eficiente. Algunos de los más comunes incluyen:
string para visualizarla.¿Cómo puedo implementar colas en programación?
La versatilidad de las colas permite adaptarlas a necesidades específicas al diseñarlas. Para implementar colas en código, se utilizan distintos métodos y estructuras que puedes personalizar según el contexto de tu programa o aplicación.
En resumen, las colas son una poderosa herramienta en programación para manejar datos de manera eficiente y lógica. ¡No dudes en experimentar con ellas y adaptarlas a tus proyectos!
Emmanuel Guerra Sánchez
Germán García
Jose Noriega
Jose Noriega
Germán García
Simon Velasquez
Nicolas Alpargatero
Gustavo Rodriguez
Agustín Emperador
Mauricio Gonzalez Falcon
Sebastián Franco
Andrés Cardona
Andrés Cardona
Jhon Freddy Tavera Blandon
En los métodos del queue hay errores en la descripción del método add y pop, lo que dice describe lo que hacen esos métodos en un Stack.
lo explico al revés no ???
Queue con Nodos
Me adelanto un poco y les comparto mi implementación de los métodos básicos que mencionó en la clase.
Código
from typing import Any from typing import Iterable from typing import Optional from node import Node class Queue: """Represents a simple queue.""" _front: Optional[Node] _rear: Optional[Node] _size: int def __init__(self, *items) -> None: """Initializes the Queue""" self._front = None self._rear = None self._size = 0 if len(items) > 0 and isinstance(items[0], Iterable): items = items[0] for item in items: self.add(item) def clear(self): """Clears the queue. Time complexity: O(1) """ self._front = None self._rear = None self._size = 0 def peek(self): """Returns the first element of the queue. Raises IndexError if the queue is empty. Time complexity: O(1) Returns: Any: First element of the queue. """ if self._front is None: raise IndexError('The queue is empty.') return self._front.value def is_empty(self) -> bool: """Check if the queue is empty. Returns: bool: True if the queue is empty. False otherwise. """ return self._front is None def add(self, value: Any) -> None: """Adds a new value to the queue. Time Complexity: O(1) Args: value (Any): Value to be added. Returns: None """ if self._front is None: self._front = Node(value) self._rear = self._front else: self._rear.next = Node(value) self._rear = self._rear.next self._size += 1 return None def pop(self): """Removes a value from the queue. Raises IndexError if the queue is empty. Time complexity: O(1) Returns: Any: Removed value. """ if self._front is None: raise IndexError('The queue is empty') value = self._front.value self._front = self._front.next self._size -= 1 return value def copy(self): """Returns a copy of the current queue. Time complexity: O(1) Returns: Queue: Copy of the current queue. """ new_queue = Queue() new_queue._front = self._front new_queue._rear = self._rear new_queue._size = self._size return new_queue def depthcopy(self): """Returns a copy of the current queue. This function will create a copy of each node in the queue. Time Complexity: O(n) Returns: Queue: Copy of the queue. """ new_queue = Queue() pointer = self._front while pointer is not None: new_queue.add(pointer.value) pointer = pointer.next return new_queue def itervalues(self) -> Iterable[Any]: """Generates an iterable of the values in the queue. Time complexity: O(n) Returns: Iterable: Iterable of the values in the queue. """ pointer = self._front while pointer is not None: yield pointer.value pointer = pointer.next return None def iternodes(self) -> Iterable[Node]: """Generates an iterable of the nodes in the queue. Returns: Iterable: Iterable of the nodes in the queue. """ pointer = self._front while pointer is not None: yield pointer pointer = pointer.next return None def __len__(self) -> int: """Returns the length of the queue when using the `len` built-in function. Time complexity: O(1) Returns: int: Number of nodes into the queue. """ return self._size def __str__(self): """Returns a string representation of the queue. Time complexity: O(n) Args: str: Representation of the queue """ return '->'.join(self.itervalues()) def __iter__(self) -> Iterable[Any]: """Generates an iterable of the values in the queue. Time complexity: O(n) Returns: Iterable: Iterable of the values in the queue. """ return self.itervalues() def __contains__(self, value: Any) -> bool: """Checks if a value is in the queue. Time complexity: O(n) Args: value: Value to be searched in the queue. Returns: bool: True if the value is in the queue. False otherwise. """ for item in self: if item == value: return True return False def __add__(self, other: Iterable) -> 'Queue': """Returns a new queue with the items of both queues. Time complexity: O(n) Args: other (Iterable): Items to be added to the current queue. Returns: Queue: New queue with the items of both queues. """ new_queue = self.depthcopy() for item in other: new_queue.add(item) return new_queue
Unittest
# Unittest import unittest # Utilities from queue import Queue class QueueTestCase(unittest.TestCase): """Queue test cases.""" def test_initialize_empty(self): """Test initialize empty queue.""" _queue = Queue() self.assertEqual(len(_queue), 0) def test_intialize_with_list(self): """Test initialize with list.""" _queue = Queue([1, 2, 3]) self.assertEqual(len(_queue), 3) for a, b in zip(_queue, [1, 2, 3]): self.assertEqual(a, b) def test_initialize_with_tuple(self): """Test initialize with tuple.""" _queue = Queue((1, 2, 3)) self.assertEqual(len(_queue), 3) for a, b in zip(_queue, [1, 2, 3]): self.assertEqual(a, b) def test_initialize_with_set(self): """Test initialize with set.""" _queue = Queue({1, 2, 3}) self.assertEqual(len(_queue), 3) for a, b in zip(_queue, [1, 2, 3]): self.assertEqual(a, b) def test_initialize_with_iterable(self): """Test initialize with iterable.""" _queue = Queue(range(1, 4)) self.assertEqual(len(_queue), 3) for a, b in zip(_queue, [1, 2, 3]): self.assertEqual(a, b) def test_is_empty(self): """Test is empty.""" _queue = Queue() self.assertTrue(_queue.is_empty()) _queue = Queue([1, 2, 3]) self.assertFalse(_queue.is_empty()) def test_add(self): """Test add.""" _queue = Queue() _queue.add(1) self.assertEqual(len(_queue), 1) _queue.add(2) self.assertEqual(len(_queue), 2) def test_peek(self): """Test peek.""" _queue = Queue() self.assertRaises(IndexError, _queue.peek) _queue = Queue([1, 2, 3]) self.assertEqual(_queue.peek(), 1) def test_pop(self): """Test pop.""" _queue = Queue([1, 2, 3]) self.assertEqual(_queue.pop(), 1) self.assertEqual(_queue.pop(), 2) self.assertEqual(_queue.pop(), 3) self.assertRaises(IndexError, _queue.pop) def test_copy(self): """Test copy.""" _queue = Queue([1, 2, 3]) queue_copy = _queue.copy() self.assertIsNot(_queue, queue_copy) self.assertEqual(len(_queue), len(queue_copy)) for a, b in zip(_queue.iternodes(), queue_copy.iternodes()): self.assertEqual(a, b) self.assertIs(a, b) def test_depthcopy(self): """Test depthcopy.""" _queue = Queue([1, 2, 3]) queue_copy: Queue = _queue.depthcopy() self.assertIsNot(_queue, queue_copy) self.assertEqual(len(_queue), len(queue_copy)) for a, b in zip(_queue.iternodes(), queue_copy.iternodes()): self.assertEqual(a, b) self.assertIsNot(a, b) def test_clear(self): """Test clear.""" _queue = Queue([1, 2, 3]) _queue.clear() self.assertEqual(len(_queue), 0) def test_contains(self): """Test contains.""" _queue = Queue([1, 2, 3]) self.assertTrue(1 in _queue) self.assertFalse(4 in _queue) def test_add_operator(self): """Test add operator.""" _queue = Queue([1, 2, 3]) _queue += [4, 5, 6] self.assertEqual(len(_queue), 6) for a, b in zip(_queue, [1, 2, 3, 4, 5, 6]): self.assertEqual(a, b)
se ve el código muy limpio, como usas las comprehentios, como usas los métodos privados con _, etc
Yo creo que lo que falto en este curso fue un Proyecto desde el Inicio, como en un curso previo se hizo PlatziBlog y se fue Modificando conforme iba enseñando cosas nuevas.
Lo que entiendo es que con estructuras de datos mas simples se puede hacer todo lo que el explico pero mil veces mas simple, sin embargo con mas consumo de recursos, considero que si creaba un proyecto con lo que ya conociamos y lo iba modificando con estas nuevas estructuras y mostraba la diferencia entre ambos todo hubiera quedado muchisimo mas claro.
Me sorprende la cantidad de gente que dejo el curso por el módulo anterior 😅 los entiendo, todo lo hice entendí fue apunta de IA.
Asi es como me ha tocado
Por si alguno no nota el mensaje subliminar de los videos... En todos hay una voz que susurra "platzi"
Puedes dar el minuto? para comprobarlo jaja.
Justo en la transición del inicio, escucha atentamente mientras suena la música y el logo pasa
Les dejo el código comnetado paso a paso para mayor entendimiento:
from node import Node # Importa la clase Node desde el archivo node.py class Stack: def __init__(self): self.top = None # Inicializa el tope de la pila como None self.size = 0 # Inicializa el tamaño de la pila como 0 def push(self, data): # Crea un nuevo nodo con el dato y apunta al nodo actual en el tope node = Node(data, self.top) if self.top: # Si la pila no está vacía node.next = self.top # El siguiente del nuevo nodo es el nodo actual en el tope self.top = node # El tope ahora es el nuevo nodo else: self.top = node # Si la pila está vacía, el nuevo nodo es el tope self.size += 1 # Incrementa el tamaño de la pila def pop(self): if self.top: # Si la pila no está vacía data = self.top.data # Obtiene el dato del nodo en el tope self.size -= 1 # Reduce el tamaño de la pila if self.top.next: # Si hay un nodo siguiente al nodo actual en el tope self.top = self.top.next # El nuevo tope es el nodo siguiente else: self.top = None # Si no hay nodo siguiente, la pila está vacía return data # Retorna el dato del nodo eliminado else: return ("The stack is empty") # Retorna un mensaje si la pila está vacía def peek(self): return self.top.data if self.top else ("The stack is empty") # Retorna el dato en el tope de la pila si la pila no está vacía, de lo contrario, retorna un mensaje def clear(self): while self.top: # Mientras la pila no esté vacía self.pop() # Elimina el nodo en el tope de la pila def search_element(self, data): if self.top: # Si la pila no está vacía current = self.top # Comienza desde el nodo en el tope while current: # Mientras haya un nodo actual if current.data == data: # Si el dato del nodo actual es igual al dato buscado return (f'Elemet {data} founded') # Retorna un mensaje indicando que el elemento fue encontrado current = current.next # Avanza al siguiente nodo return (f'Elemet {data} not founded') # Retorna un mensaje indicando que el elemento no fue encontrado ```Les dejo el código comnetado paso a paso para mayor entendimiento:
Les dejo el código comnetado paso a paso para mayor entendimiento:
from node import Node # Importa la clase Node desde el archivo node.py
class Stack:
def __init__(self):
self.top = None # Inicializa el tope de la pila como None
self.size = 0 # Inicializa el tamaño de la pila como 0
def push(self, data):
# Crea un nuevo nodo con el dato y apunta al nodo actual en el tope
node = Node(data, self.top)
if self.top: # Si la pila no está vacía
node.next = self.top # El siguiente del nuevo nodo es el nodo actual en el tope
self.top = node # El tope ahora es el nuevo nodo
else:
self.top = node # Si la pila está vacía, el nuevo nodo es el tope
self.size += 1 # Incrementa el tamaño de la pila
def pop(self):
if self.top: # Si la pila no está vacía
data = self.top.data # Obtiene el dato del nodo en el tope
self.size -= 1 # Reduce el tamaño de la pila
if self.top.next: # Si hay un nodo siguiente al nodo actual en el tope
self.top = self.top.next # El nuevo tope es el nodo siguiente
else:
self.top = None # Si no hay nodo siguiente, la pila está vacía
return data # Retorna el dato del nodo eliminado
else:
return ("The stack is empty") # Retorna un mensaje si la pila está vacía
def peek(self):
return self.top.data if self.top else ("The stack is empty") # Retorna el dato en el tope de la pila si la pila no está vacía, de lo contrario, retorna un mensaje
def clear(self):
while self.top: # Mientras la pila no esté vacía
self.pop() # Elimina el nodo en el tope de la pila
def search_element(self, data):
if self.top: # Si la pila no está vacía
current = self.top # Comienza desde el nodo en el tope
while current: # Mientras haya un nodo actual
if current.data == data: # Si el dato del nodo actual es igual al dato buscado
return (f'Elemet {data} founded') # Retorna un mensaje indicando que el elemento fue encontrado
current = current.next # Avanza al siguiente nodo
return (f'Elemet {data} not founded') # Retorna un mensaje indicando que el elemento no fue encontrado
Las queues, también conocidas como colas, son una estructura de datos lineal que sigue el principio de FIFO (First In, First Out), lo que significa que el primer elemento en entrar es el primero en ser atendido o procesado .
En una cola, los elementos se agregan al final y se eliminan desde el frente. Esto se asemeja a una fila en la vida real, donde la primera persona en llegar es la primera en ser atendida.
Las operaciones principales en una cola son:
Enqueue (encolar):
Dequeue (desencolar):
Front (frente):
Rear (trasero):
Is Empty (está vacía):
Las queues se utilizan comúnmente en situaciones donde es necesario mantener un orden de llegada y procesamiento, como:
Procesamiento de tareas en un sistema operativo. Implementación de buffers en comunicaciones de red. Planificación de tareas en algoritmos de búsqueda y exploración. Control de flujo de datos en aplicaciones que manejan eventos y procesos en serie. A continuación, se muestra un ejemplo simple de implementación de una cola en Python utilizando una lista: