A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle, meaning the element added first to the queue is the first one to be removed. This property makes queues ideal for managing tasks in the order they arrive, such as scheduling tasks, handling requests, and more.
In Java, queues can be implemented using various data structures like arrays, linked lists, and the Java Collections Framework.
An array-based queue uses a fixed-size array. This is a straightforward implementation but is not suitable for dynamic resizing.
class ArrayQueue {
private int front, rear, size;
private int capacity;
private int[] queue;
public ArrayQueue(int capacity) {
this.capacity = capacity;
front = size = 0;
rear = capacity - 1;
queue = new int[this.capacity];
}
boolean isFull() {
return (size == capacity);
}
boolean isEmpty() {
return (size == 0);
}
void enqueue(int item) {
if (isFull()) {
System.out.println("Queue is full");
return;
}
rear = (rear + 1) % capacity;
queue[rear] = item;
size++;
}
int dequeue() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
int item = queue[front];
front = (front + 1) % capacity;
size--;
return item;
}
int front() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
return queue[front];
}
int rear() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
return queue[rear];
}
}
A linked list-based queue provides dynamic sizing and is often the preferred implementation for queues that need to grow and shrink dynamically.
class LinkedListQueue {
class Node {
int data;
Node next;
Node(int item) {
data = item;
next = null;
}
}
private Node front, rear;
public LinkedListQueue() {
front = rear = null;
}
boolean isEmpty() {
return front == null;
}
void enqueue(int item) {
Node newNode = new Node(item);
if (rear == null) {
front = rear = newNode;
return;
}
rear.next = newNode;
rear = newNode;
}
int dequeue() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
int item = front.data;
front = front.next;
if (front == null) rear = null;
return item;
}
int front() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
return front.data;
}
int rear() {
if (isEmpty()) {
System.out.println("Queue is empty");
return Integer.MIN_VALUE;
}
return rear.data;
}
}
Java provides a built-in Queue interface, which is implemented by classes like LinkedList and PriorityQueue. The LinkedList class provides an easy-to-use implementation for FIFO queues.
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();
q.add(10);
q.add(20);
q.add(30);
System.out.println("Front element: " + q.peek());
q.remove();
System.out.println("After dequeue, front element: " + q.peek());
System.out.println("Queue size: " + q.size());
}
}
A priority queue is a type of queue where each element is assigned a priority, and elements with higher priorities are dequeued before elements with lower priorities.
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(30);
pq.add(10);
pq.add(20);
System.out.println("Priority Queue: " + pq);
while (!pq.isEmpty()) {
System.out.println("Dequeued: " + pq.poll());
}
}
}
A deque (double-ended queue) allows insertion and deletion at both ends, providing flexibility to operate as both a stack and a queue.
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeExample {
public static void main(String[] args) {
Deque<Integer> dq = new ArrayDeque<>();
dq.addFirst(10);
dq.addLast(20);
dq.addFirst(5);
System.out.println("Deque: " + dq);
System.out.println("Removed from front: " + dq.removeFirst());
System.out.println("Removed from back: " + dq.removeLast());
}
}
The performance of a queue implementation depends on the data structure used: