Skip to content

Queue

A queue is a First-In-First-Out (FIFO) data structure where elements are added at one end (rear) and removed from the other end (front). It follows the principle that the first element added is the first one to be removed.

Features

  • FIFO ordering - First In, First Out access pattern
  • Efficient operations - O(1) enqueue, dequeue, and peek operations
  • Dynamic size - automatically grows and shrinks as needed
  • Memory efficient - uses singly linked list for optimal memory usage
  • Type safe - generic implementation with type checking
  • Iterator support - can iterate from front to rear
  • Utility operations - search, count, reverse, and copy functionality

Time Complexities

Operation Time Complexity Description
Enqueue O(1) Add element to rear
Dequeue O(1) Remove element from front
Front O(1) View front element
Rear O(1) View rear element
Search O(n) Find element position
Count O(n) Count occurrences
Clear O(1) Remove all elements
Copy O(n) Create shallow copy
Reverse O(n) Reverse queue order
Size/Length O(1) Get number of elements

Space Complexity: O(n) where n is the number of elements

Basic Usage

Creating and Initializing

from algo.data_structs.stacks_queues.queue import Queue

# Create empty queue
queue = Queue()

# Check if empty
print(queue.is_empty())    # True
print(len(queue))          # 0
print(queue.size())        # 0

# Queue is generic - can specify type
int_queue = Queue[int]()
str_queue = Queue[str]()

Adding Elements (Enqueue)

# Enqueue individual elements
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)

print(len(queue))          # 3
print(queue.front())       # 1 (first element added)
print(queue.rear())        # 3 (last element added)

# Enqueue multiple elements using extend
queue.extend([4, 5, 6])
print(queue.rear())        # 6 (last element added)
print(len(queue))          # 6

# Extend with different iterables
queue.extend((7, 8))       # Tuple
queue.extend([9, 10])      # List
print(queue.to_list())     # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (front to rear)

Viewing Elements

# Peek at front element without removing
front_element = queue.front()
print(front_element)       # 1
print(len(queue))          # Still same size

# Peek at rear element without removing
rear_element = queue.rear()
print(rear_element)        # 10

# Check if queue contains element
print(5 in queue)          # True
print(99 in queue)         # False

# Convert to list (front to rear order)
elements = queue.to_list()
print(elements)            # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Removing Elements (Dequeue)

# Dequeue elements one by one (FIFO order)
dequeued = queue.dequeue()
print(dequeued)            # 1 (first element added)
print(len(queue))          # 9

# Dequeue multiple elements
results = []
for _ in range(3):
    results.append(queue.dequeue())
print(results)             # [2, 3, 4]

# Dequeue until empty
while not queue.is_empty():
    element = queue.dequeue()
    print(f"Dequeued: {element}")

print(queue.is_empty())    # True

Clearing the Queue

# Add some elements
queue.extend([1, 2, 3, 4, 5])
print(len(queue))          # 5

# Clear all elements
queue.clear()
print(len(queue))          # 0
print(queue.is_empty())    # True

Search and Count Operations

Finding Elements

queue = Queue()
queue.extend([1, 2, 3, 2, 4, 2])  # [1, 2, 3, 2, 4, 2] (front to rear)

# Search returns position from front (0-based)
print(queue.search(1))     # 0 (front element)
print(queue.search(2))     # 1 (first occurrence of 2)
print(queue.search(3))     # 2 (third position from front)
print(queue.search(4))     # 4 (fifth position from front)
print(queue.search(99))    # -1 (not found)

# Check membership
print(2 in queue)          # True
print(99 in queue)         # False

Counting Elements

# Count occurrences of elements
print(queue.count(2))      # 3 (appears 3 times)
print(queue.count(1))      # 1 (appears once)
print(queue.count(99))     # 0 (not present)

# Count all elements
total_elements = len(queue)
print(total_elements)      # 6

Iteration and Traversal

queue = Queue()
queue.extend(['apple', 'banana', 'cherry', 'date'])

# Iterate from front to rear
print("Queue contents (front to rear):")
for item in queue:
    print(item)  # apple, banana, cherry, date

# Convert to list for processing
items = list(queue)
print(items)               # ['apple', 'banana', 'cherry', 'date']

# Enumerate with position
for i, item in enumerate(queue):
    print(f"Position {i}: {item}")

Working with Different Types

String Elements

words = Queue()
words.enqueue("hello")
words.enqueue("world")
words.enqueue("python")

print(words.front())       # "hello"
print("world" in words)    # True
print(words.count("hello")) # 1

Numeric Elements

numbers = Queue()
numbers.extend([1, 2, 3, 4, 5])
numbers.enqueue(3.14)
numbers.enqueue(42)

print(numbers.front())     # 1
print(3.14 in numbers)     # True
print(len(numbers))        # 7

Mixed Types

mixed = Queue()
mixed.enqueue("string")
mixed.enqueue(42)
mixed.enqueue([1, 2, 3])   # Lists can be stored
mixed.enqueue(True)

print(mixed.front())       # "string"
print(42 in mixed)         # True
print(len(mixed))          # 4

Custom Objects

class Task:
    def __init__(self, name: str, priority: int):
        self.name = name
        self.priority = priority

    def __eq__(self, other):
        return isinstance(other, Task) and self.name == other.name

    def __str__(self):
        return f"Task({self.name}, priority={self.priority})"

tasks = Queue()
task1 = Task("Write code", 1)
task2 = Task("Test code", 2)
task3 = Task("Deploy", 3)

tasks.enqueue(task1)
tasks.enqueue(task2)
tasks.enqueue(task3)

print(tasks.front())       # Task(Write code, priority=1)
print(task1 in tasks)      # True
print(len(tasks))          # 3

Queue Manipulation

Copying Queues

original = Queue()
original.extend([1, 2, 3, 4, 5])

# Create a copy
copy_queue = original.copy()

# Verify they have same contents
print(copy_queue.to_list() == original.to_list())  # True
print(len(copy_queue) == len(original))             # True

# Verify they're independent
original.enqueue(6)
print(len(original))       # 6
print(len(copy_queue))     # 5 (unchanged)

copy_queue.enqueue(99)
print(99 in original)      # False
print(99 in copy_queue)    # True

Reversing Queues

queue = Queue()
queue.extend([1, 2, 3, 4, 5])
print(queue.to_list())     # [1, 2, 3, 4, 5] (front to rear)

# Reverse the queue
queue.reverse()
print(queue.to_list())     # [5, 4, 3, 2, 1] (front to rear)
print(queue.front())       # 5 (was rear, now front)
print(queue.rear())        # 1 (was front, now rear)

String Representation

# Empty queue
empty_queue = Queue()
print(str(empty_queue))    # Queue([])

# Non-empty queue
queue = Queue()
queue.extend([1, 2, 3])
print(str(queue))          # Queue([1 <- 2 <- 3] <- rear)

# Detailed representation for debugging
print(repr(queue))         # Queue(size=3, front=1, rear=3)

Error Handling

queue = Queue()

# Safe operations on empty queue
print(queue.is_empty())    # True
print(len(queue))          # 0
print(queue.search(42))    # -1
print(queue.count(42))     # 0
print(42 in queue)         # False

# Operations that raise errors on empty queue
try:
    queue.dequeue()
except IndexError as e:
    print(f"Error: {e}")   # Error: Cannot dequeue from empty queue

try:
    queue.front()
except IndexError as e:
    print(f"Error: {e}")   # Error: Cannot peek front of empty queue

try:
    queue.rear()
except IndexError as e:
    print(f"Error: {e}")   # Error: Cannot peek rear of empty queue

Common Patterns

Building from Iterables

# From list
queue = Queue()
queue.extend([1, 2, 3, 4, 5])

# From tuple
queue2 = Queue()
queue2.extend((1, 2, 3))

# From range
queue3 = Queue()
queue3.extend(range(10))

# From another queue
queue4 = Queue()
queue4.extend(queue)  # Copy elements from queue

FIFO Processing

# Process items in order
items = ["first", "second", "third", "fourth"]
queue = Queue()

# Load items
for item in items:
    queue.enqueue(item)

# Process in FIFO order
processed = []
while not queue.is_empty():
    item = queue.dequeue()
    processed.append(f"Processed: {item}")

print(processed)
# ['Processed: first', 'Processed: second', 'Processed: third', 'Processed: fourth']

Task Scheduling

class TaskScheduler:
    def __init__(self):
        self.task_queue = Queue()
        self.completed_tasks = []

    def add_task(self, task_name: str):
        """Add a task to the queue."""
        self.task_queue.enqueue(task_name)
        print(f"Added task: {task_name}")

    def process_next_task(self):
        """Process the next task in the queue."""
        if not self.task_queue.is_empty():
            task = self.task_queue.dequeue()
            self.completed_tasks.append(task)
            print(f"Processing task: {task}")
            return task
        else:
            print("No tasks to process")
            return None

    def show_queue_status(self):
        """Show current queue status."""
        print(f"Tasks in queue: {len(self.task_queue)}")
        print(f"Completed tasks: {len(self.completed_tasks)}")
        if not self.task_queue.is_empty():
            print(f"Next task: {self.task_queue.front()}")

# Usage
scheduler = TaskScheduler()
scheduler.add_task("Send email")
scheduler.add_task("Update database")
scheduler.add_task("Generate report")

scheduler.show_queue_status()
scheduler.process_next_task()
scheduler.process_next_task()
scheduler.show_queue_status()

Producer-Consumer Pattern

class Buffer:
    def __init__(self, max_size: int = 10):
        self.queue = Queue()
        self.max_size = max_size

    def produce(self, item):
        """Producer adds items to buffer."""
        if len(self.queue) < self.max_size:
            self.queue.enqueue(item)
            print(f"Produced: {item} (buffer size: {len(self.queue)})")
            return True
        else:
            print(f"Buffer full! Cannot produce: {item}")
            return False

    def consume(self):
        """Consumer takes items from buffer."""
        if not self.queue.is_empty():
            item = self.queue.dequeue()
            print(f"Consumed: {item} (buffer size: {len(self.queue)})")
            return item
        else:
            print("Buffer empty! Nothing to consume")
            return None

    def peek_next(self):
        """Peek at next item to be consumed."""
        if not self.queue.is_empty():
            return self.queue.front()
        return None

# Usage
buffer = Buffer(max_size=3)

# Producer adds items
for i in range(5):
    buffer.produce(f"item_{i}")

# Consumer processes items
for _ in range(3):
    buffer.consume()

# Producer adds more
buffer.produce("item_5")
buffer.produce("item_6")
def bfs_traversal(graph, start_node):
    """Perform breadth-first search traversal using a queue."""
    visited = set()
    queue = Queue()
    result = []

    queue.enqueue(start_node)
    visited.add(start_node)

    while not queue.is_empty():
        current_node = queue.dequeue()
        result.append(current_node)

        # Add unvisited neighbors to queue
        for neighbor in graph.get(current_node, []):
            if neighbor not in visited:
                visited.add(neighbor)
                queue.enqueue(neighbor)

    return result

# Example graph representation
graph = {
    'A': ['B', 'C'],
    'B': ['A', 'D', 'E'],
    'C': ['A', 'F'],
    'D': ['B'],
    'E': ['B', 'F'],
    'F': ['C', 'E']
}

# Perform BFS starting from 'A'
traversal_order = bfs_traversal(graph, 'A')
print(f"BFS traversal: {traversal_order}")
# Output: ['A', 'B', 'C', 'D', 'E', 'F'] (or similar order)

Practical Applications

class PrintJob:
    def __init__(self, document_name: str, pages: int, priority: str = "normal"):
        self.document_name = document_name
        self.pages = pages
        self.priority = priority
        self.timestamp = time.time() if 'time' in globals() else 0

    def __str__(self):
        return f"PrintJob({self.document_name}, {self.pages} pages, {self.priority})"

class PrintQueue:
    def __init__(self):
        self.normal_queue = Queue()
        self.high_priority_queue = Queue()
        self.current_job = None

    def add_job(self, job: PrintJob):
        """Add a print job to the appropriate queue."""
        if job.priority == "high":
            self.high_priority_queue.enqueue(job)
            print(f"Added high priority job: {job.document_name}")
        else:
            self.normal_queue.enqueue(job)
            print(f"Added normal job: {job.document_name}")

    def process_next_job(self):
        """Process the next print job (high priority first)."""
        if not self.high_priority_queue.is_empty():
            job = self.high_priority_queue.dequeue()
        elif not self.normal_queue.is_empty():
            job = self.normal_queue.dequeue()
        else:
            print("No jobs in queue")
            return None

        self.current_job = job
        print(f"Processing: {job}")
        return job

    def get_queue_status(self):
        """Get current queue status."""
        total_jobs = len(self.normal_queue) + len(self.high_priority_queue)
        return {
            "total_jobs": total_jobs,
            "high_priority": len(self.high_priority_queue),
            "normal_priority": len(self.normal_queue),
            "current_job": str(self.current_job) if self.current_job else None
        }

# Usage
printer = PrintQueue()
printer.add_job(PrintJob("report.pdf", 10))
printer.add_job(PrintJob("urgent.pdf", 2, "high"))
printer.add_job(PrintJob("memo.pdf", 1))

print(printer.get_queue_status())
printer.process_next_job()  # Should process urgent.pdf first
printer.process_next_job()  # Then report.pdf

Web Server Request Queue

class HttpRequest:
    def __init__(self, method: str, url: str, client_ip: str):
        self.method = method
        self.url = url
        self.client_ip = client_ip
        self.timestamp = time.time() if 'time' in globals() else 0

    def __str__(self):
        return f"{self.method} {self.url} from {self.client_ip}"

class WebServer:
    def __init__(self, max_concurrent_requests: int = 5):
        self.request_queue = Queue()
        self.processing_requests = []
        self.max_concurrent = max_concurrent_requests
        self.completed_requests = 0

    def receive_request(self, request: HttpRequest):
        """Receive and queue a new request."""
        self.request_queue.enqueue(request)
        print(f"Queued: {request}")

    def process_requests(self):
        """Process requests from the queue."""
        # Start new requests if we have capacity
        while (len(self.processing_requests) < self.max_concurrent and 
               not self.request_queue.is_empty()):
            request = self.request_queue.dequeue()
            self.processing_requests.append(request)
            print(f"Processing: {request}")

        # Simulate completing some requests
        if self.processing_requests:
            completed = self.processing_requests.pop(0)
            self.completed_requests += 1
            print(f"Completed: {completed}")

    def get_server_status(self):
        """Get current server status."""
        return {
            "queued_requests": len(self.request_queue),
            "processing_requests": len(self.processing_requests),
            "completed_requests": self.completed_requests,
            "next_in_queue": str(self.request_queue.front()) if not self.request_queue.is_empty() else None
        }

# Usage
server = WebServer(max_concurrent_requests=2)

# Simulate incoming requests
requests = [
    HttpRequest("GET", "/index.html", "192.168.1.1"),
    HttpRequest("POST", "/api/data", "192.168.1.2"),
    HttpRequest("GET", "/about.html", "192.168.1.3"),
    HttpRequest("GET", "/contact.html", "192.168.1.4"),
]

for req in requests:
    server.receive_request(req)

# Process requests
for _ in range(6):  # Simulate several processing cycles
    server.process_requests()
    print(f"Status: {server.get_server_status()}")
    print("---")

Cache with LRU Eviction

class LRUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.cache = {}  # key -> value
        self.access_order = Queue()  # Track access order for LRU

    def get(self, key):
        """Get value by key, updating access order."""
        if key in self.cache:
            # Remove from queue and re-add to mark as recently used
            temp_queue = Queue()
            while not self.access_order.is_empty():
                item = self.access_order.dequeue()
                if item != key:
                    temp_queue.enqueue(item)

            # Restore queue and add key as most recent
            while not temp_queue.is_empty():
                self.access_order.enqueue(temp_queue.dequeue())
            self.access_order.enqueue(key)

            return self.cache[key]
        return None

    def put(self, key, value):
        """Put key-value pair, evicting LRU if needed."""
        if key in self.cache:
            # Update existing key
            self.cache[key] = value
            self.get(key)  # Update access order
        else:
            # Add new key
            if len(self.cache) >= self.capacity:
                # Evict least recently used
                lru_key = self.access_order.dequeue()
                del self.cache[lru_key]
                print(f"Evicted LRU key: {lru_key}")

            self.cache[key] = value
            self.access_order.enqueue(key)
            print(f"Added: {key} = {value}")

    def show_cache_state(self):
        """Show current cache state."""
        print(f"Cache: {self.cache}")
        print(f"Access order (LRU to MRU): {self.access_order.to_list()}")

# Usage
cache = LRUCache(capacity=3)

cache.put("A", 1)
cache.put("B", 2)
cache.put("C", 3)
cache.show_cache_state()

print(f"Get A: {cache.get('A')}")  # A becomes most recent
cache.show_cache_state()

cache.put("D", 4)  # Should evict B (least recently used)
cache.show_cache_state()

Event Processing System

class Event:
    def __init__(self, event_type: str, data: dict, priority: int = 0):
        self.event_type = event_type
        self.data = data
        self.priority = priority
        self.timestamp = time.time() if 'time' in globals() else 0

    def __str__(self):
        return f"Event({self.event_type}, priority={self.priority})"

class EventProcessor:
    def __init__(self):
        self.event_queue = Queue()
        self.handlers = {}
        self.processed_count = 0

    def register_handler(self, event_type: str, handler_func):
        """Register a handler function for an event type."""
        self.handlers[event_type] = handler_func

    def emit_event(self, event: Event):
        """Add an event to the processing queue."""
        self.event_queue.enqueue(event)
        print(f"Emitted: {event}")

    def process_events(self, max_events: int = None):
        """Process events from the queue."""
        processed = 0

        while not self.event_queue.is_empty():
            if max_events and processed >= max_events:
                break

            event = self.event_queue.dequeue()

            # Find and execute handler
            if event.event_type in self.handlers:
                try:
                    self.handlers[event.event_type](event)
                    print(f"Processed: {event}")
                    self.processed_count += 1
                    processed += 1
                except Exception as e:
                    print(f"Error processing {event}: {e}")
            else:
                print(f"No handler for event type: {event.event_type}")

        return processed

    def get_queue_info(self):
        """Get information about the event queue."""
        return {
            "pending_events": len(self.event_queue),
            "total_processed": self.processed_count,
            "next_event": str(self.event_queue.front()) if not self.event_queue.is_empty() else None
        }

# Usage
processor = EventProcessor()

# Register event handlers
def handle_user_login(event):
    user = event.data.get('username')
    print(f"  User {user} logged in")

def handle_file_upload(event):
    filename = event.data.get('filename')
    size = event.data.get('size')
    print(f"  File {filename} uploaded ({size} bytes)")

def handle_error(event):
    error_msg = event.data.get('message')
    print(f"  Error occurred: {error_msg}")

processor.register_handler("user_login", handle_user_login)
processor.register_handler("file_upload", handle_file_upload)
processor.register_handler("error", handle_error)

# Emit events
events = [
    Event("user_login", {"username": "alice"}),
    Event("file_upload", {"filename": "document.pdf", "size": 1024}),
    Event("user_login", {"username": "bob"}),
    Event("error", {"message": "Database connection failed"}),
    Event("file_upload", {"filename": "image.jpg", "size": 2048}),
]

for event in events:
    processor.emit_event(event)

# Process all events
print("\nProcessing events:")
processor.process_events()
print(f"\nFinal status: {processor.get_queue_info()}")

Use Cases

When to Use Queues

Good for:

  • Task scheduling and job processing
  • Breadth-first search algorithms
  • Buffer for data streams
  • Print job management
  • Process scheduling
  • Event handling systems
  • Producer-consumer patterns
  • Request handling in web servers

Examples:

# Task processing
task_queue = Queue()
task_queue.enqueue("process_data")
task_queue.enqueue("send_email")
task_queue.enqueue("backup_files")

# Buffer for streaming data
data_buffer = Queue()
data_buffer.enqueue(data_chunk_1)
data_buffer.enqueue(data_chunk_2)

# BFS traversal
bfs_queue = Queue()
bfs_queue.enqueue(root_node)

# Request handling
request_queue = Queue()
request_queue.enqueue(http_request)

When NOT to Use Queues

Avoid for:

  • Random access to elements (use arrays/lists)
  • LIFO processing (use stacks)
  • Priority-based processing (use priority queues)
  • Frequent middle insertions/deletions

Better alternatives:

# For random access, use list
random_access = [1, 2, 3, 4, 5]
print(random_access[2])  # Direct access to index 2

# For LIFO, use stack
from algo.data_structs.stacks_queues.stack import Stack
lifo_stack = Stack()
lifo_stack.push(1)
lifo_stack.pop()  # LIFO behavior

# For priority-based processing, use priority queue
from algo.data_structs.trees.priority_queue import PriorityQueue
priority_queue = PriorityQueue()
priority_queue.put("urgent_task", 1)
priority_queue.put("normal_task", 5)

Performance Characteristics

Time Complexity Analysis

  • Enqueue/Dequeue operations: O(1) - constant time
  • Front/Rear operations: O(1) - constant time
  • Search operations: O(n) - linear time
  • Memory allocation: O(1) per element (linked list)
  • Space overhead: Minimal (only node pointers)

Memory Efficiency

# Queue uses singly linked list internally
# Memory per element: data + one pointer
# No pre-allocation of fixed arrays
# Memory grows/shrinks dynamically

queue = Queue()
print(f"Empty queue memory efficient: {queue.is_empty()}")

# Memory usage scales linearly with elements
for i in range(1000):
    queue.enqueue(i)
# Only allocates memory for actual elements

Comparison with Other Data Structures

Operation Queue List Deque Stack
Add Front N/A O(n) O(1) O(1)
Add Rear O(1) O(1) O(1) N/A
Remove Front O(1) O(n) O(1) N/A
Remove Rear N/A O(1) O(1) O(1)
Random Access O(n) O(1) O(n) O(n)
Memory Overhead Low Medium Low Low
Use Case FIFO Random Access Both Ends LIFO

API Reference

Queue Implementation

A queue is a First-In-First-Out (FIFO) data structure where elements are added at the rear (enqueue) and removed from the front (dequeue). It follows the principle that the first element added is the first one to be removed.

Key Features:

  • FIFO (First In, First Out) ordering
  • Enqueue operation adds element to rear
  • Dequeue operation removes element from front
  • Front operation views front element without removing it
  • Dynamic size allocation

Common Use Cases:

  • Task scheduling and job queues
  • Breadth-first search (BFS) algorithms
  • Buffer for data streams
  • Print job management
  • Process scheduling in operating systems

Time Complexities:

  • Enqueue: O(1)
  • Dequeue: O(1)
  • Front: O(1)
  • Size: O(1)
  • Search: O(n)

Space Complexity: O(n)

Queue()

Bases: Generic[T]

A queue implementation using a singly linked list as the underlying data structure.

This implementation provides efficient O(1) enqueue and dequeue operations by maintaining references to both head and tail of the linked list.

Initialize an empty queue.

__contains__(value)

Check if a value exists in the queue.

__iter__()

Return an iterator over the queue elements.

Note: Iteration goes from front to rear (oldest to newest).

__len__()

Return the number of elements in the queue.

__repr__()

Return detailed string representation for debugging.

__str__()

Return string representation of the queue.

clear()

Remove all elements from the queue.

Time Complexity: O(1)

copy()

Create a shallow copy of the queue.

Time Complexity: O(n)

Returns:

Type Description
Queue[T]

A new Queue with the same elements

count(item)

Count the number of occurrences of an item in the queue.

Time Complexity: O(n)

Parameters:

Name Type Description Default
item T

Item to count

required

Returns:

Type Description
int

Number of occurrences

dequeue()

Remove and return the front element from the queue.

Time Complexity: O(1)

Returns:

Type Description
T

The front element of the queue

Raises:

Type Description
IndexError

If the queue is empty

enqueue(item)

Add an element to the rear of the queue.

Time Complexity: O(1)

Parameters:

Name Type Description Default
item T

Element to add to the queue

required

extend(iterable)

Enqueue all elements from an iterable onto the queue.

Time Complexity: O(k) where k is the number of elements

Parameters:

Name Type Description Default
iterable Any

Iterable containing elements to enqueue

required
Note

Elements are enqueued in order, maintaining FIFO behavior.

front()

Return the front element without removing it.

Time Complexity: O(1)

Returns:

Type Description
T

The front element of the queue

Raises:

Type Description
IndexError

If the queue is empty

is_empty()

Check if the queue is empty.

Time Complexity: O(1)

Returns:

Type Description
bool

True if the queue is empty, False otherwise

rear()

Return the rear element without removing it.

Time Complexity: O(1)

Returns:

Type Description
T

The rear element of the queue

Raises:

Type Description
IndexError

If the queue is empty

reverse()

Reverse the queue in place.

Time Complexity: O(n)

Note

After reversal, the front element becomes the rear element.

search(item)

Search for an item in the queue and return its position from the front.

Time Complexity: O(n)

Parameters:

Name Type Description Default
item T

Item to search for

required

Returns:

Type Description
int

Position from front (0-based), or -1 if not found

Note

Front element has position 0, second element has position 1, etc.

size()

Get the number of elements in the queue.

Time Complexity: O(1)

Returns:

Type Description
int

The number of elements in the queue

to_list()

Convert the queue to a Python list.

Time Complexity: O(n)

Returns:

Type Description
list[T]

A Python list with elements from front to rear