From 70368a757e8d37b9f3dd96af4ca535275cb39580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20A=2E=20Rodr=C3=ADguez?= Date: Thu, 28 Oct 2021 11:43:24 -0300 Subject: [PATCH] Implement Circular Queue using linked lists. Fixes TheAlgorithms#5361 (#5587) * CircularQueueLinkedList: empty list, trivial implementation TheAlgorithms#5361 * CircularQueueLinkedList: single element list TheAlgorithms#5361 * CircularQueueLinkedList: refactor, no que empty attribute TheAlgorithms#5361 * CircularQueueLinkedList: refactor TheAlgorithms#5361 * CircularQueueLinkedList: changed internal data structure to use double linked list TheAlgorithms#5361 * CircularQueueLinkedList: enqueue test cases added TheAlgorithms#5361 * CircularQueueLinkedList: track full queue TheAlgorithms#5361 * CircularQueueLinkedList: adding functions description TheAlgorithms#5361 * CircularQueueLinkedList: type hints TheAlgorithms#5361 * CircularQueueLinkedList: algorithm explanation TheAlgorithms#5361 * CircularQueueLinkedList: missing type hints TheAlgorithms#5361 * CircularQueueLinkedList: more missing type hints TheAlgorithms#5361 * Update data_structures/queue/circular_queue_linked_list.py Co-authored-by: John Law --- .../queue/circular_queue_linked_list.py | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 data_structures/queue/circular_queue_linked_list.py diff --git a/data_structures/queue/circular_queue_linked_list.py b/data_structures/queue/circular_queue_linked_list.py new file mode 100644 index 000000000..1878403bd --- /dev/null +++ b/data_structures/queue/circular_queue_linked_list.py @@ -0,0 +1,150 @@ +# Implementation of Circular Queue using linked lists +# https://en.wikipedia.org/wiki/Circular_buffer + +from typing import Any + + +class CircularQueueLinkedList: + """ + Circular FIFO list with the given capacity (default queue length : 6) + + >>> cq = CircularQueueLinkedList(2) + >>> cq.enqueue('a') + >>> cq.enqueue('b') + >>> cq.enqueue('c') + Traceback (most recent call last): + ... + Exception: Full Queue + """ + + def __init__(self, initial_capacity: int = 6) -> None: + self.front = None + self.rear = None + self.create_linked_list(initial_capacity) + + def create_linked_list(self, initial_capacity: int) -> None: + current_node = Node() + self.front = current_node + self.rear = current_node + previous_node = current_node + for i in range(1, initial_capacity): + current_node = Node() + previous_node.next = current_node + current_node.prev = previous_node + previous_node = current_node + previous_node.next = self.front + self.front.prev = previous_node + + def is_empty(self) -> bool: + """ + Checks where the queue is empty or not + >>> cq = CircularQueueLinkedList() + >>> cq.is_empty() + True + >>> cq.enqueue('a') + >>> cq.is_empty() + False + >>> cq.dequeue() + 'a' + >>> cq.is_empty() + True + """ + return self.front == self.rear and self.front.data is None + + def first(self) -> Any: + """ + Returns the first element of the queue + >>> cq = CircularQueueLinkedList() + >>> cq.first() + Traceback (most recent call last): + ... + Exception: Empty Queue + >>> cq.enqueue('a') + >>> cq.first() + 'a' + >>> cq.dequeue() + 'a' + >>> cq.first() + Traceback (most recent call last): + ... + Exception: Empty Queue + >>> cq.enqueue('b') + >>> cq.enqueue('c') + >>> cq.first() + 'b' + """ + self.check_can_perform_operation() + return self.front.data + + def enqueue(self, data: Any) -> None: + """ + Saves data at the end of the queue + + >>> cq = CircularQueueLinkedList() + >>> cq.enqueue('a') + >>> cq.enqueue('b') + >>> cq.dequeue() + 'a' + >>> cq.dequeue() + 'b' + >>> cq.dequeue() + Traceback (most recent call last): + ... + Exception: Empty Queue + """ + self.check_is_full() + if self.is_empty(): + self.rear.data = data + else: + self.rear = self.rear.next + self.rear.data = data + + def dequeue(self) -> Any: + """ + Removes and retrieves the first element of the queue + + >>> cq = CircularQueueLinkedList() + >>> cq.dequeue() + Traceback (most recent call last): + ... + Exception: Empty Queue + >>> cq.enqueue('a') + >>> cq.dequeue() + 'a' + >>> cq.dequeue() + Traceback (most recent call last): + ... + Exception: Empty Queue + """ + self.check_can_perform_operation() + if self.front == self.rear: + data = self.front.data + self.front.data = None + return data + + old_front = self.front + self.front = old_front.next + data = old_front.data + old_front.data = None + return data + + def check_can_perform_operation(self) -> None: + if self.is_empty(): + raise Exception("Empty Queue") + + def check_is_full(self) -> None: + if self.rear.next == self.front: + raise Exception("Full Queue") + + +class Node: + def __init__(self) -> None: + self.data = None + self.next = None + self.prev = None + + +if __name__ == "__main__": + import doctest + + doctest.testmod()