Linked Queue
Linked Queue A Linked Queue is a linear data structure that follows the FIFO (First-In-First-Out) principle. It consists of nodes, where each node contains a value and a reference to the next node in the queue. The front of the queue is where the removal or dequeuing happens, and the rear is where the insertion or enqueueing takes place.
The operations supported by a Linked Queue are:
enqueue(value)
: Inserts an element at the rear of the queue.dequeue()
: Removes and returns the element at the front of the queue.is_empty()
: Checks if the queue is empty.size()
: Returns the number of elements in the queue.front()
: Returns the value of the element at the front of the queue without removing it.
Here's an example implementation of a Linked Queue in Python with proper comments explaining each step:
class Node:
def __init__(self, value):
self.value = value
self.next = None
class LinkedQueue:
def __init__(self):
self.front = None # Points to the front of the queue
self.rear = None # Points to the rear of the queue
self.size = 0 # Keeps track of the number of elements in the queue
def enqueue(self, value):
new_node = Node(value)
if self.is_empty():
self.front = new_node
else:
self.rear.next = new_node
self.rear = new_node
self.size += 1
def dequeue(self):
if self.is_empty():
raise Exception("Queue is empty")
value = self.front.value
self.front = self.front.next
self.size -= 1
if self.is_empty():
self.rear = None
return value
def is_empty(self):
return self.size == 0
def size(self):
return self.size
def front(self):
if self.is_empty():
raise Exception("Queue is empty")
return self.front.value
Now, let's solve a question from LeetCode using the Linked Queue concept.
Question: Implement Stack using Queues
Implement a stack using queues. The stack should support the following operations: push()
, pop()
, top()
, and empty()
.
class MyStack:
def __init__(self):
self.queue = LinkedQueue()
def push(self, x):
# Enqueue the new element
self.queue.enqueue(x)
# Rotate the elements to bring the new element to the front
for _ in range(self.queue.size - 1):
self.queue.enqueue(self.queue.dequeue())
def pop(self):
if self.empty():
raise Exception("Stack is empty")
# Dequeue and return the front element
return self.queue.dequeue()
def top(self):
if self.empty():
raise Exception("Stack is empty")
# Return the front element without dequeuing it
return self.queue.front()
def empty(self):
return self.queue.is_empty()
In this solution, we use a Linked Queue to implement a Stack. The push
operation is implemented by enqueuing the new element and rotating the existing elements to bring the new element to the front. The pop
operation dequeues and returns the front element. The top
operation returns the front element without dequeuing it. The empty
operation checks if the stack is empty.
The time complexity of push
, pop
, top
, and empty
operations is O(n) in the worst case, where n is the number of elements in the stack. The worst case occurs when the new element is pushed and all existing elements are rotated. The space complexity is O(n) to store the elements in the Linked Queue.
Let's solve the question "Binary Tree Level Order Traversal" using the Linked Queue concept.
Question: Binary Tree Level Order Traversal Given a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example:
Input: [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
Output: [[3],[9,20],[15,7]]
To solve this problem, we can use a Linked Queue to perform a breadth-first traversal of the binary tree. We will enqueue each level's nodes and process them level by level.
Here's the Python code to solve the problem:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.val = value
self.left = left
self.right = right
def level_order_traversal(root):
if not root:
return []
result = []
queue = LinkedQueue()
queue.enqueue(root)
while not queue.is_empty():
level = []
level_size = queue.size
for _ in range(level_size):
node = queue.dequeue()
level.append(node.val)
if node.left:
queue.enqueue(node.left)
if node.right:
queue.enqueue(node.right)
result.append(level)
return result
# Test the code with the given example
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)
print(level_order_traversal(root)) # Output: [[3], [9, 20], [15, 7]]
The level_order_traversal
function takes the root of a binary tree as input and performs a level order traversal using a Linked Queue. It initializes an empty result list and a queue. The root is enqueued, and then a loop iterates until the queue is empty. In each iteration, the nodes at the current level are dequeued, and their values are added to the level
list. If the dequeued node has left and right children, they are enqueued. The level
list is then appended to the result list. Finally, the result list containing the level order traversal is returned.
The time complexity of this solution is O(n), where n is the number of nodes in the binary tree. We need to visit each node once. The space complexity is also O(n) since, in the worst case, the Linked Queue can hold all the nodes at the maximum level, which is n/2 in a complete binary tree.