Problem
Implement a queue data structure using a fixed-size array. The queue should support the following operations:
- enqueue(x): Add an element
x
to the end of the queue. - dequeue(): Remove the element from the front of the queue.
- isEmpty(): Check if the queue is empty.
- isFull(): Check if the queue is full.
- front(): Get the front element of the queue without removing it.
- size(): Get the number of elements currently in the queue.
Examples
Example 1:
Input:
Operations: ["enqueue(1)", "enqueue(2)", "front()", "dequeue()", "isEmpty()"]
Output: [null, null, 1, 1, false]
Explanation:
1. Enqueue 1: The queue becomes [1].
2. Enqueue 2: The queue becomes [1, 2].
3. Front: The front element is 1.
4. Dequeue: Remove the front element 1. The queue becomes [2].
5. isEmpty: The queue is not empty, hence returns false.
Solution
A queue data structure allows elements to be added at the rear and removed from the front. An array can be effectively used to implement a fixed-size queue by maintaining two pointers: one for the front and one for the rear. Additionally, we maintain a variable to keep track of the number of elements in the queue.
Method 1 - Bad dequeue function
Here is how we can implement it:
- Enqueue: Add an element to the queue after ensuring it is not full. If
rear < n
, indicating that the array has space, store the element atarr[rear]
and incrementrear
by 1. Ifrear == n
, it is an Overflow condition as the array is full. - Dequeue: Remove an element from the queue if there is at least one element to delete, i.e.,
rear > 0
. Delete the element atarr[front]
, and shift all remaining elements to the left by one position to allow for the dequeuing of the next element at the front. - Front: Retrieve the front element from the queue, i.e.,
arr[front]
, if the queue is not empty. - Display: Print all elements of the queue. Traverse and print elements from index
front
torear
if the queue is not empty.
Code
Java
public class FixedArrayQueueBadRemove {
private int[] arr; // array to store queue elements
private int front; // front points to the front element in the queue
private int rear; // rear points to the last element in the queue
private int capacity; // maximum capacity of the queue
private int count; // current size of the queue
// Constructor to initialize a queue
public FixedArrayQueueBadRemove(int size) {
arr = new int[size];
capacity = size;
front = 0;
rear = 0;
count = 0;
}
// Insert an element at the rear
public boolean enqueue(int item) {
if (isFull()) {
throw new IllegalStateException("Queue is full");
}
arr[rear++] = item;
count++;
return true;
}
// Remove and return the front element
public int dequeue() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
int temp = arr[front];
for (int i = 0; i < rear - 1; i++) {
arr[i] = arr[i + 1];
}
arr[--rear] = 0;
count--;
return temp;
}
// Return the front element without removing it
public int peek() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
return arr[front];
}
// Return the size of the queue
public int size() {
return count;
}
// Check if the queue is empty
public boolean isEmpty() {
return count == 0;
}
// Check if the queue is full
public boolean isFull() {
return rear == capacity;
}
}
Python
class FixedArrayQueueBadRemove:
def __init__(self, size: int):
self.arr = [0] * size # array to store queue elements
self.front = 0 # front points to the front element in the queue
self.rear = 0 # rear points to the last element in the queue
self.capacity = size # maximum capacity of the queue
self.count = 0 # current size of the queue
# Insert an element at the rear
def enqueue(self, item: int) -> bool:
if self.is_full():
raise OverflowError("Queue is full")
self.arr[self.rear] = item
self.rear += 1
self.count += 1
return True
# Remove and return the front element
def dequeue(self) -> int:
if self.is_empty():
raise IndexError("Queue is empty")
temp = self.arr[self.front]
for i in range(self.rear - 1):
self.arr[i] = self.arr[i + 1]
self.rear -= 1
self.count -= 1
self.arr[self.rear] = 0
return temp
# Return the front element without removing it
def peek(self) -> int:
if self.is_empty():
raise IndexError("Queue is empty")
return self.arr[self.front]
# Return the size of the queue
def size(self) -> int:
return self.count
# Check if the queue is empty
def is_empty(self) -> bool:
return self.count == 0
# Check if the queue is full
def is_full(self) -> bool:
return self.rear == self.capacity
Complexity
- ⏰ Time complexity
- Enqueue:
O(1)
. - Dequeue:
O(n)
due to the shifting of elements. - Front:
O(1)
. - Display:
O(n)
.
- Enqueue:
- 🧺 Space complexity:
O(n)
wheren
is the capacity of the array.
Method 2 - Using modulo operator
Here is a better approach:
- Initialize an array of a fixed size.
- Pointers: Use
front
andrear
pointers to manage the enqueue and dequeue operations. - enqueue(x): Add the element
x
at the position indicated by therear
pointer and update the pointer. - dequeue(): Remove the element from the position indicated by the
front
pointer and update the pointer. - isEmpty(): Check if the
count
of elements is zero. - isFull(): Check if the
count
of elements is equal to the size of the array. - front(): Return the element at the
front
pointer. - size(): Return the count of the elements in the queue.
Code
Java
class FixedSizeQueue {
private int[] arr;
private int front, rear, count, size;
public FixedSizeQueue(int size) {
this.size = size;
arr = new int[size];
front = 0;
rear = -1;
count = 0;
}
public boolean enqueue(int item) {
if (isFull()) {
throw new IllegalStateException("Queue is full");
}
rear = (rear + 1) % size;
arr[rear] = item;
count += 1;
return true;
}
public int dequeue() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
int item = arr[front];
front = (front + 1) % size;
count -= 1;
return item;
}
public int front() {
if (isEmpty()) {
throw new IllegalStateException("Queue is empty");
}
return arr[front];
}
public boolean isEmpty() {
return count == 0;
}
public boolean isFull() {
return count == size;
}
public int size() {
return count;
}
}
Python
class FixedSizeQueue:
def __init__(self, size: int):
self.size = size
self.arr = [None] * size
self.front = 0
self.rear = -1
self.count = 0
def enqueue(self, item: int) -> bool:
if self.is_full():
raise OverflowError("Queue is full")
self.rear = (self.rear + 1) % self.size
self.arr[self.rear] = item
self.count += 1
return True
def dequeue(self) -> int:
if self.is_empty():
raise IndexError("Queue is empty")
item = self.arr[self.front]
self.front = (self.front + 1) % self.size
self.count -= 1
return item
def front(self) -> int:
if self.is_empty():
raise IndexError("Queue is empty")
return self.arr[self.front]
def is_empty(self) -> bool:
return self.count == 0
def is_full(self) -> bool:
return self.count == self.size
def size(self) -> int:
return self.count
Complexity
- ⏰ Time complexity:
O(1)
. The complexity for all operations (enqueue
,dequeue
,isEmpty
,isFull
,front
, andsize
) isO(1)
since we are using direct indexing and simple arithmetic operations. - 🧺 Space complexity:
O(n)