What is an Abstract Data Type?
An abstract data type (ADT) defines the behavior of a data structure—what operations it supports and how they behave—but it doesn’t define how it’s implemented.
For example, a Queue ADT can be implemented using:
- Arrays
- Linked Lists
- Stacks (using two stacks to form a queue)
- Heaps
So think of ADT as a blueprint or a contract that can be implemented in multiple ways.
What is a Queue?
A Queue is a linear data structure that follows the FIFO (First In, First Out) principle.
ATM Analogy:
- The first person to arrive is the first one served.
- Everyone else must wait in line until it’s their turn.
This concept maps perfectly to how a queue operates.
FIFO Explained:
- First item inserted → First item removed
- Example:
- Enqueue:
10 → 6 → 18 → 1 → 56
- Dequeue order:
10 → 6 → 18 → 1 → 56
- Enqueue:
Basic Operations on a Queue
Operation | Description |
enqueue() | Adds (inserts) an item to the back of the queue |
dequeue() | Removes the item from the front of the queue |
peek() / front() | Returns the front item without removing it |
dequeue()
removes the element, but peek()
just reads it.
Queue Use Case Example
Let’s walk through a simple example:
Initial State:
Queue is empty.
Sequence of enqueue()
:
enqueue(10) → Queue: [10] enqueue(6) → Queue: [10, 6] enqueue(18) → Queue: [10, 6, 18] enqueue(1) → Queue: [10, 6, 18, 1] enqueue(56) → Queue: [10, 6, 18, 1, 56]
Now perform dequeue()
:
dequeue() → 10 → Queue: [6, 18, 1, 56] dequeue() → 6 → Queue: [18, 1, 56] dequeue() → 18 → Queue: [1, 56] dequeue() → 1 → Queue: [56] dequeue() → 56 → Queue: []
At every point, only the first item inserted is accessible. You can’t jump to the middle or end of the queue.
Internal Implementation
A queue can be implemented using:
- Arrays (fixed size, may require resizing)
- Linked Lists (dynamic size, efficient enqueue and dequeue)
- Two Stacks (to simulate queue behavior)
Real-Life Applications of Queues
1. Operating Systems
- Thread Scheduling: OS schedules threads using a queue to manage task execution.
- CPU Scheduling: Tasks (processes) are put in a queue, and the CPU handles them one at a time.
2. Smartphone Apps
Imagine using your smartphone:
- Tapping the screen
- Opening multiple apps
- Downloading files
- Getting notifications
All of these actions generate tasks, and the OS needs to handle them one by one.
The queue stores:
- Touch events
- Network requests
- UI updates
- API call responses
The CPU processes them in order, ensuring a smooth user experience.
Implementation in Java
Node.java
package Queue; public class Node<T extends Comparable<T>> { private T data; private Node<T> nextNode; public Node(T data) { this.data = data; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Node<T> getNextNode() { return nextNode; } public void setNextNode(Node<T> nextNode) { this.nextNode = nextNode; } @Override public String toString() { return this.data.toString(); } }
Queue.java
package Queue; public class Queue<T extends Comparable<T>> { private Node<T> firstNode; private Node<T> lastNode; private int count; public boolean isEmpty(){ return this.firstNode == null; } public int size(){ return this.count; } // O(1) public void enqueue(T newData){ this.count++; Node<T> oldLastNode = this.lastNode; this.lastNode = new Node<>(newData); this.lastNode.setNextNode(null); if( isEmpty() ){ this.firstNode = this.lastNode; }else{ oldLastNode.setNextNode(this.lastNode); } } // O(1) public T dequeue(){ this.count--; T dataToDequeue = this.firstNode.getData(); this.firstNode=this.firstNode.getNextNode(); if( isEmpty() ){ this.lastNode = null; } return dataToDequeue; } }
App.java
package Queue; public class App { /** * @param args */ public static void main(String[] args) { Queue<Integer> queue = new Queue<Integer>(); queue.enqueue(10); queue.enqueue(20); queue.enqueue(30); System.out.println(queue.dequeue()); System.out.println(queue.size()); } }