Data Structures: Queues
Overview of the Queue Abstract Data Type (ADT)
Definition: The Queue ADT stores arbitrary objects where insertions and deletions follow the First-In First-Out (FIFO) scheme.
Conceptual Analogy: The operations are similar to a queue at a bank or a shop, where the first person in line is the first person served.
Structural Mechanics: * Insertions: Occur at the rear (back) of the queue. * Removals: Occur at the front of the queue.
Queue Operations and Exceptions
Main Operations: *
enqueue(object): Inserts an element at the end of the queue. *object dequeue(): Removes and returns the element at the front of the queue.Auxiliary Operations: *
object first(): Returns the element at the front without removing it. *integer len(): Returns the number of elements currently stored. *boolean is_empty(): Indicates whether the queue contains any elements.Exceptions: *
EmptyQueueException: This error is thrown when attempting to executedequeueorfront(also referred to asfirst) on a queue that contains no elements.
Operational Example Trace
Operation | Return Value | Queue State (Front to Last) |
|---|---|---|
| - |
|
| - |
|
|
| |
|
| |
|
|
|
|
| |
|
|
|
| "error" |
|
| - |
|
| - |
|
|
| |
| - |
|
|
| |
|
|
Applications of Queues
Direct Applications: * Waiting lists. * Customer service centers. * Access to shared resources (e.g., a network printer). * Multiprogramming environments.
Indirect Applications: * As an auxiliary data structure for broader algorithms. * As a component within other complex data structures.
Array-Based Queue implementation
Underlying Structure: A Python list is utilized as the internal storage structure.
Circular Fashion Logic: * The implementation uses an array of a fixed size in a circular manner. * This approach avoids the need to shift elements up when an item is removed from position , which would otherwise lead to time complexity.
State Variables: *
f: An integer representing the index of the front element. *size: An integer representing the total number of elements currently in the queue. *r: A conceptual pointer representing the first element available after the end of the queue.Configurations: * Normal Configuration: The front index
fprecedes the rear indexrlinearly. * Wrapped-Around Configuration: The queue elements start near the end of the array and wrap back to the beginning, meaningr < f.
Deep Dive: Queue Algorithmic Logic
Algorithm
isEmpty(): * Returns the result of the boolean check(size == 0).Algorithm
first(): * Returns the element located at indexfof the arrayQ.Algorithm
len(): * Returns the value of thesizevariable.Algorithm
enqueue(o): * Check capacity:if size() == len(Q), then callresize(2 * len(Q)). * Calculate insert position:r = (f + size) mod len(Q). The modulo operator is necessary to calculate the insert position correctly within a circular array, allowing the index to wrap back to after reaching the end of the physical list. * Placement:Q[r] = o. * Update:size = size + 1.Algorithm
dequeue(): * Empty Check:if isEmpty(), throwEmptyQueueException. * Retrieval:o = Q[f]. * Cleanup:Q[f] = null(helpful for garbage collection). * Update index:f = (f + 1) mod len(Q). * Update count:size = size - 1. * Return retrieved objecto.Algorithm
resize(n): * Trigger: Occurs whensize == len(Q). * Process: 1. Store the existing data in a temporary variableoldQ. 2. Initialize the main listQto a new sizenfilled withnullvalues. 3. Set a pointerwalk = f(the old front index). 4. Loopxfrom tosize - 1: * AssignQ[x] = oldQ[walk]. * Updatewalk = (walk + 1) mod len(oldQ)to traverse the old circular array. 5. Reset the front indexf = 0to realign the queue with the start of the new array.
Python Implementation Details (ArrayQueue Class)
Instance Variables: *
self._data: A reference to a list instance with a fixed capacity. *self._size: An integer representing the current number of elements stored (distinct from the list's capacity). *self._front: An integer index of the first element in the queue.Default Settings: *
DEFAULT_CAPACITY = 10is used for all new queue instances.Implementation of Key Methods: *
__init__(self): Creates an empty queue whereself._datais initialized to[None]multiplied by the default capacity, and bothself._sizeandself._frontare set to . *first(self): Raises anEmptyexception if the queue is empty; otherwise, returnsself._data[self._front]. *dequeue(self): * RaisesEmptyexception if needed. * Capturesanswer = self._data[self._front]. * Explicitly setsself._data[self._front] = Noneto assist the garbage collector. * Calculates new front:self._front = (self._front + 1) % len(self._data). * Decrementsself._sizeby 1. * Returnsanswer. *enqueue(self, e): * If the internal list is full (self._size == len(self._data)), it doubles the array size viaself._resize(2 * len(self._data)). * Calculates available index:avail = (self._front + self._size) % len(self._data). * Setsself._data[avail] = eand incrementsself._sizeby 1. *_resize(self, cap): * Maintains a reference to theoldlist. * Allocates a newself._datalist of the specifiedcaplength. * Iterates through existing elements only (for k in range(self._size)). * Intentionally shifts indices so the newself._frontbecomes .
Time Complexity and Extended Types
Efficiency: All standard queue operations execute in constant time , including: *
Q.enqueue(e)(amortized, due to resizing). *Q.dequeue(). *Q.first(). *Q.is_empty(). *len(Q).Double-Ended Queues (Deques): An ADT that allows elements to be added and deleted from both the front and the back of the queue. While the standard queue is FIFO, the deque offers broader flexibility.