Introduction
A queue is a linear data structure that follows the First In, First Out (FIFO) principle, where elements are added (enqueued) to the rear of the queue and removed (dequeued) from the front. Unlike an array-based implementation, a linked list-based queue dynamically adjusts its size as elements are added or removed. This guide will walk you through writing a Java program that implements a queue using a singly linked list.
Problem Statement
Create a Java program that:
- Implements a queue using a linked list.
- Provides methods to perform standard queue operations:
enqueue,dequeue,peek, andisEmpty. - Displays the queue contents after various operations.
Example:
- Input: Enqueue elements:
10, 20, 30 - Operations:
enqueue(40),dequeue(),peek() - Output:
- After enqueuing 40:
10 -> 20 -> 30 -> 40 -> null - After dequeuing:
20 -> 30 -> 40 -> null - Peeked element:
20
- After enqueuing 40:
Solution Steps
- Create the Node Structure: Define a
Nodeclass to represent each element in the queue. - Create the Queue Structure: Define a
Queueclass to manage the queue using a linked list, including methods for standard queue operations. - Implement Queue Operations: Implement methods to enqueue elements into the queue, dequeue elements from the queue, peek at the front element, and check if the queue is empty.
- Display the Queue: Output the queue’s contents after performing various operations.
Java Program
// Java Program to Implement a Queue Using Linked List
// Author: https://www.rameshfadatare.com/
// Step 1: Define the Node class to represent each element in the queue
class Node {
int data;
Node next;
// Constructor to initialize the node
public Node(int data) {
this.data = data;
this.next = null;
}
}
// Step 2: Define the Queue class to manage the queue operations using a linked list
class Queue {
private Node front, rear;
// Constructor to initialize the queue (initially empty)
public Queue() {
this.front = this.rear = null;
}
// Step 3: Method to enqueue an element into the queue
public void enqueue(int value) {
// Create a new node with the given value
Node newNode = new Node(value);
// If the queue is empty, both front and rear point to the new node
if (this.rear == null) {
this.front = this.rear = newNode;
System.out.println("Enqueued " + value + " into the queue.");
return;
}
// Otherwise, add the new node at the end of the queue and change the rear
this.rear.next = newNode;
this.rear = newNode;
System.out.println("Enqueued " + value + " into the queue.");
}
// Step 4: Method to dequeue an element from the queue
public int dequeue() {
if (isEmpty()) {
System.out.println("Queue is empty. Unable to dequeue.");
return -1; // Return a sentinel value indicating the queue is empty
}
// Move the front pointer to the next node
int dequeuedValue = this.front.data;
this.front = this.front.next;
// If the front becomes null, then the queue is empty, so set rear to null
if (this.front == null) {
this.rear = null;
}
System.out.println("Dequeued " + dequeuedValue + " from the queue.");
return dequeuedValue;
}
// Step 5: Method to peek at the front element of the queue
public int peek() {
if (isEmpty()) {
System.out.println("Queue is empty. Nothing to peek.");
return -1; // Return a sentinel value indicating the queue is empty
} else {
System.out.println("Peeked at the front element: " + this.front.data);
return this.front.data;
}
}
// Step 6: Method to check if the queue is empty
public boolean isEmpty() {
return (this.front == null);
}
// Step 7: Method to display the contents of the queue
public void display() {
if (isEmpty()) {
System.out.println("Queue is empty.");
} else {
System.out.print("Queue contents: ");
Node current = front;
while (current != null) {
System.out.print(current.data + " -> ");
current = current.next;
}
System.out.println("null");
}
}
}
public class QueueDemo {
public static void main(String[] args) {
Queue queue = new Queue(); // Create a queue
// Enqueue elements into the queue
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.display();
// Enqueue another element
queue.enqueue(40);
queue.display();
// Dequeue an element from the queue
queue.dequeue();
queue.display();
// Peek at the front element
queue.peek();
queue.display();
// Dequeue all elements to test underflow
queue.dequeue();
queue.dequeue();
queue.dequeue();
queue.dequeue(); // This dequeue should trigger an underflow condition
queue.display();
}
}
Explanation
Step 1: Define the Node Class
- The
Nodeclass represents a single element in the queue. Each node containsdataand a reference to the next node (next). - The constructor initializes the node with data and sets the
nextpointer tonull.
Step 2: Define the Queue Class
- The
Queueclass manages the queue operations using a linked list. The class contains two pointers,frontandrear, which point to the first and last nodes in the queue, respectively. - The queue is initialized as empty, with both
frontandrearset tonull.
Step 3: Enqueue an Element into the Queue
- The
enqueue()method adds a new node to the rear of the queue:- A new node is created with the given value.
- If the queue is empty, both
frontandrearpoint to the new node. - Otherwise, the
nextpointer of therearnode is updated to point to the new node, andrearis updated to the new node.
Step 4: Dequeue an Element from the Queue
- The
dequeue()method removes and returns the front element of the queue:- If the queue is empty, an underflow message is displayed.
- Otherwise, the
frontpointer is updated to point to the next node, and the data of the dequeued node is returned. - If the queue becomes empty after the dequeue operation,
rearis set tonull.
Step 5: Peek at the Front Element of the Queue
- The
peek()method returns the front element without removing it:- If the queue is empty, an appropriate message is displayed.
- Otherwise, the
frontelement’s data is returned.
Step 6: Check if the Queue is Empty
- The
isEmpty()method checks if the queue is empty by verifying iffrontisnull.
Step 7: Display the Queue Contents
- The
display()method prints all elements currently in the queue:- The queue is traversed from the
frontto therear, printing each element’s data.
- The queue is traversed from the
Output Example
Enqueued 10 into the queue.
Enqueued 20 into the queue.
Enqueued 30 into the queue.
Queue contents: 10 -> 20 -> 30 -> null
Enqueued 40 into the queue.
Queue contents: 10 -> 20 -> 30 -> 40 -> null
Dequeued 10 from the queue.
Queue contents: 20 -> 30 -> 40 -> null
Peeked at the front element: 20
Queue contents: 20 -> 30 -> 40 -> null
Dequeued 20 from the queue.
Dequeued 30 from the queue.
Dequeued 40 from the queue.
Queue is empty. Unable to dequeue.
Queue is empty.
Conclusion
This Java program demonstrates how to implement a queue using a linked list, including handling underflow conditions when attempting to dequeue from an empty queue. The program efficiently manages queue operations, providing dynamic growth and shrinkage, unlike array-based queues. This exercise is valuable for understanding how to implement and manipulate queues using linked lists in Java programming.