Step 4 of 5

80% Complete

Peek Operation

Learn how to view elements without removing them

The Peek Operation

The peek operation (sometimes called front) returns the element at the front of the queue without removing it. It's like looking at who's next in line without serving them.

When implementing a queue, the peek operation is responsible for:

  • Accessing the element at the front of the queue
  • Returning the element without modifying the queue
  • Checking if the queue is empty before attempting to peek

Array-based Implementation

In a simple array-based implementation, we access the first element of the array.

Peek Operation (Simple Array-based)
peek() {
// Check if queue is empty
if (this.isEmpty()) {
return null; // Or throw an error
}
// Return the front element without removing it
return this.items[0];
}
Queue with peek operation:
10
20
30
40
peek() returns 10 without removing it

Key Points:

  • Time Complexity: O(1) - constant time
  • Does not modify the queue structure
  • Always check if the queue is empty before peeking
  • Simple to implement using array indexing

Optimized Array Implementation

In an optimized array implementation with front and rear pointers, we access the element at the front pointer.

Peek Operation (Optimized Array-based)
class OptimizedQueue {
constructor() {
this.items = {};
this.front = 0;
this.rear = 0;
}
// Enqueue and dequeue methods (for reference)
// ...
peek() {
// Check if queue is empty
if (this.isEmpty()) {
return null;
}
// Return the front element without removing it
return this.items[this.front];
}
isEmpty() {
return this.rear - this.front === 0;
}
}

Key Points:

  • Time Complexity: O(1) - constant time
  • Uses the front pointer to access the first element
  • Works with the object-based implementation

Linked List-based Implementation

In a linked list-based implementation, we access the value of the head node.

Peek Operation (Linked List-based)
class LinkedListQueue {
constructor() {
this.head = null; // Front of the queue
this.tail = null; // Rear of the queue
this.size = 0;
}
// Enqueue and dequeue methods (for reference)
// ...
peek() {
// Check if queue is empty
if (this.isEmpty()) {
return null;
}
// Return the value of the head node without removing it
return this.head.value;
}
isEmpty() {
return this.size === 0;
}
}

Key Points:

  • Time Complexity: O(1) - constant time
  • Accesses the value property of the head node
  • No traversal required since we have a direct reference to the head

Circular Queue Implementation

In a circular queue, the peek operation accesses the element at the front position.

Peek Operation (Circular Queue)
class CircularQueue {
constructor(capacity = 5) {
this.items = new Array(capacity);
this.capacity = capacity;
this.front = 0;
this.rear = 0;
this.size = 0;
}
// Enqueue and dequeue methods (for reference)
// ...
peek() {
// Check if queue is empty
if (this.isEmpty()) {
return null;
}
// Return the front element without removing it
return this.items[this.front];
}
isEmpty() {
return this.size === 0;
}
}

Key Points:

  • Time Complexity: O(1) - constant time
  • Uses the front pointer to access the first element
  • Works with the circular array implementation

Additional Utility Methods

Besides the core operations (enqueue, dequeue, peek), queues typically support these utility methods:

isEmpty

isEmpty() {
return this.size === 0;
// Or for array-based: return this.items.length === 0;
}

Checks if the queue has no elements.

size

size() {
return this.size;
// Or for array-based: return this.items.length;
}

Returns the number of elements in the queue.

clear

clear() {
// For array-based
this.items = [];
// For linked list-based
this.head = null;
this.tail = null;
this.size = 0;
// For circular queue
this.items = new Array(this.capacity);
this.front = 0;
this.rear = 0;
this.size = 0;
}

Removes all elements from the queue.

Practical Example

Let's see a complete example of a queue with all operations:

class Queue {
constructor() {
this.items = [];
}
// Add an element to the queue
enqueue(element) {
this.items.push(element);
return this;
}
// Remove and return the front element
dequeue() {
if (this.isEmpty()) {
return null;
}
return this.items.shift();
}
// Return the front element without removing it
peek() {
if (this.isEmpty()) {
return null;
}
return this.items[0];
}
// Check if the queue is empty
isEmpty() {
return this.items.length === 0;
}
// Get the size of the queue
size() {
return this.items.length;
}
// Clear the queue
clear() {
this.items = [];
}
}
// Usage example
const queue = new Queue();
queue.enqueue(10).enqueue(20).enqueue(30);
console.log("Queue:", queue.items); // [10, 20, 30]
console.log("Front element:", queue.peek()); // 10
console.log("Queue after peek:", queue.items); // [10, 20, 30] (unchanged)
const firstItem = queue.dequeue();
console.log("Dequeued item:", firstItem); // 10
console.log("Queue after dequeue:", queue.items); // [20, 30]
console.log("New front element:", queue.peek()); // 20
queue.clear();
console.log("Queue after clear:", queue.items); // []
console.log("Is queue empty?", queue.isEmpty()); // true

Check Your Understanding

Next Steps

Now that you understand all the core operations of queues (enqueue, dequeue, and peek), let's explore practical applications of queues in the next section.