A Queue ADT stores arbitrary objects and follows the First-In, First-Out (FIFO) principle.
The first element inserted into the queue is the first one removed.

Queue Discipline (FIFO)
| Term | Meaning |
|---|---|
| Front | Position where elements are removed |
| Rear (Back) | Position where elements are added |

| Operation | Description |
|---|---|
enqueue(x) |
Insert element x at the rear |
dequeue() |
Remove and return the front element |
peek() / front() |
Return the front element without removing it |
is_empty() |
Check whether the queue is empty |
size() |
Return the number of elements |
Exceptions: Attempting the execution of dequeue or front on an empty queue throws an EmptyQueueException
items: a container to store queue elements
A queue can be efficiently implemented using an array of fixed size N in a circular fashion.
Instead of shifting elements, the array is treated as circular, wrapping around when the end is reached.

Two integer variables are used to track the queue:
Important rule
- Array location r is always kept empty
- This helps distinguish between full and empty states
1
2
Array indices: 0 1 2 3 4 ... N-1
Queue wraps around using modulo arithmetic

1
2
Algorithm size()
return (N - f + r) mod N
Explanation:
1
2
Algorithm isEmpty()
return (f = r)
Explanation:
The enqueue operation inserts an element at position r
After insertion: r <- (r + 1) mod N
1
2
3
4
5
6
Algorithm enqueue(o)
if size() = N <- 1 then
throw FullQueueException
else
Q[r] <- o
r <- (r + 1) mod N
In this case:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Queue:
def __init__(self):
self.items = []
def is_empty(self):
return len(self.items) == 0
def enqueue(self, item):
self.items.append(item)
def dequeue(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.items.pop(0)
def peek(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.items[0]
def size(self):
return len(self.items)
| Operation | Return Value | Queue (first <- Q <- last) |
|---|---|---|
| Q.enqueue(5) | – | [5] |
| Q.enqueue(3) | – | [5, 3] |
| len(Q) | 2 | [5, 3] |
| Q.dequeue() | 5 | [3] |
| Q.is_empty() | False | [3] |
| Q.dequeue() | 3 | [] |
| Q.is_empty() | True | [] |
| Q.dequeue() | “error” | [] |
| Q.enqueue(7) | – | [7] |
| Q.enqueue(9) | – | [7, 9] |
| Q.first() | 7 | [7, 9] |
| Q.enqueue(4) | – | [7, 9, 4] |
| len(Q) | 3 | [7, 9, 4] |
| Q.dequeue() | 7 | [9, 4] |
Examples:
1
2
3
4
5
6
7
8
9
q = Queue()
q.enqueue(5)
q.enqueue(10)
q.enqueue(15)
print(q.dequeue()) # Output: 5
print(q.peek()) # Output: 10
print(q.size()) # Output: 2
Direct applications
Indirect applications
Array-based Queue
Queue Operations
1
2
3
4
5
Algorithm size()
return (N - f + r) mod N
Algorithm isEmpty()
return (f = r)
1
2
Operation enqueue throws an exception if the array is full
This exception is implementation-dependent
| Operation | Time Complexity | Explanation |
|---|---|---|
enqueue |
O(1) | Append to end of list |
dequeue |
O(n) | All elements shift left |
peek |
O(1) | Direct index access |
is_empty |
O(1) | Length check |
Using list.pop(0) is inefficient for large queues.
Python provides deque (double-ended queue), optimized for FIFO operations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from collections import deque
class Queue:
def __init__(self):
self.items = deque()
def is_empty(self):
return len(self.items) == 0
def enqueue(self, item):
self.items.append(item)
def dequeue(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.items.popleft()
def peek(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.items[0]
def size(self):
return len(self.items)
| Operation | Time Complexity |
|---|---|
enqueue |
O(1) |
dequeue |
O(1) |
peek |
O(1) |
| Implementation | Pros | Cons |
|---|---|---|
| List-based | Simple, intuitive | Slow dequeue() |
| Deque-based | Fast, scalable | Requires import |
| Circular Queue | Memory efficient | More complex logic |
An Abstract Data Type (ADT) is an abstraction of a data structure. It defines what operations are supported and how the data behaves, without specifying how the data is implemented.
A Stack is a linear data structure that follows the LIFO principle: \(LIFO:Last-In, First-Out\)
This means:
An ADT specifies:

Example: ADT for a Stock Trading System
Data Stored: Buy and sell orders
Supported Operations
1
2
3
order buy(stock, shares, price)
order sell(stock, shares, price)
void cancel(order)
Error Conditions
A stack has one accessible end only, called the Top.
| Term | Meaning |
|---|---|
| Top | Position where elements are added and removed |
| Bottom | The first element added |
An Abstract Data Type (ADT) defines the behavior of a stack, independent of implementation.
| Operation | Description |
|---|---|
push(x) |
Insert element x onto the top |
pop() |
Remove and return the top element |
peek() / top() |
Return the top element without removing it |
is_empty() |
Check if the stack is empty |
size() |
Return the number of elements |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Stack:
def __init__(self):
self.items = []
def is_empty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items.pop()
def peek(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items[-1]
def size(self):
return len(self.items)
1
2
3
4
5
6
7
8
9
s = Stack()
s.push(10)
s.push(20)
s.push(30)
print(s.pop()) # Output: 30
print(s.peek()) # Output: 20
print(s.size()) # Output: 2
| Operation | Time Complexity | Explanation |
|---|---|---|
push |
O(1) | Append to end of list |
pop |
O(1) | Remove from end |
peek |
O(1) | Direct index access |
is_empty |
O(1) | Length check |
Very efficient using Python lists.
What’s happen? When:
- Occurs when pushing onto a full stack (bounded stack)
- Occurs when popping from an empty stack
| Application | Description |
|---|---|
| Function calls | Call stack in memory |
| Undo / Redo | Text editors |
| Expression evaluation | Postfix / Prefix |
| Syntax checking | Parentheses matching |
| DFS | Graph traversal |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class BoundedStack:
def __init__(self, capacity):
if capacity <= 0:
raise ValueError("Capacity must be a positive integer")
self.capacity = capacity
self.items = []
def is_empty(self):
return len(self.items) == 0
def is_full(self):
return len(self.items) == self.capacity
def push(self, item):
if self.is_full():
raise OverflowError("Stack overflow: cannot push onto a full stack")
self.items.append(item)
def pop(self):
if self.is_empty():
raise IndexError("Stack underflow: cannot pop from an empty stack")
return self.items.pop()
def peek(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items[-1]
def size(self):
return len(self.items)
def __str__(self):
return f"Stack(bottom → top): {self.items}"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
stack = BoundedStack(3)
stack.push(10)
stack.push(20)
stack.push(30)
print(stack) # Stack(bottom → top): [10, 20, 30]
print(stack.peek()) # 30
# Stack overflow
# stack.push(40) # OverflowError
print(stack.pop()) # 30
print(stack.pop()) # 20
print(stack.size()) # 1
# Stack underflow
# stack.pop()
# stack.pop() # IndexError
| Operation | Time Complexity |
|---|---|
push |
O(1) |
pop |
O(1) |
peek |
O(1) |
is_empty |
O(1) |
is_full |
O(1) |
In many real-world service systems such as banks, public service centers, hospitals, and customer support offices, service requests are typically processed in a First In – First Out (FIFO) order.
Without a proper queue management mechanism:
Therefore, the problem is to design and implement a queue-based service management system that:
The system must operate in a console-based environment and must not use any database.
The system must support the following functions:
| Attribute | Data Type | Description |
|---|---|---|
| id | int | Customer identifier |
| name | string | Customer name |
| service_type | string | Type of service |
| arrival_time | int or float | Arrival time |
— Input —
Main menu:
1
2
3
4
5
6
7
8
===== SERVICE QUEUE MANAGEMENT =====
1. Add customer to queue
2. Serve next customer
3. View next customer
4. Display queue
5. Show statistics
6. Exit
===================================
Input for adding a customer:
1
2
3
4
Customer ID: 101
Customer Name: Nguyen Van A
Service Type: Payment
Arrival Time: 12.5
— Output —
When a customer is successfully added:
1
Customer added to queue successfully.
When serving a customer:
1
2
3
4
Serving customer:
ID: 101
Name: Nguyen Van A
Service Type: Payment
When viewing the next customer:
1
2
3
4
Next customer in queue:
ID: 102
Name: Tran Thi B
Service Type: Registration
When the queue is empty:
1
The queue is empty. No customer to serve.
When displaying the entire queue:
1
2
3
Current Queue:
1. ID: 102 - Tran Thi B - Registration
2. ID: 103 - Le Van C - Inquiry
When showing statistics:
1
2
3
Total customers served: 5
Customers waiting: 2
Average waiting time: 4.2 minutes
In many areas of computer science such as compilers, calculators, and programming language interpreters, expressions (arithmetic or logical) must be processed in a specific order.
However, expressions written in infix notation (e.g. 3 + 4 * 2) are not easy for computers to evaluate directly because operator precedence and parentheses must be handled correctly.
The problem is to design a system that:
The system must be implemented as a console-based program without using any external libraries for expression evaluation.
—Input—
Main menu:
1
2
3
4
5
6
7
===== STACK EXPRESSION PROCESSOR =====
1. Enter infix expression
2. Convert infix to postfix
3. Display postfix expression
4. Evaluate postfix expression
0. Exit
=====================================
Example input:
1
Enter infix expression: 3 + (4 * 5)
—Output—
After converting infix to postfix:
1
Postfix expression: 3 4 5 * +
After evaluating postfix expression:
1
Evaluation result: 23
If the expression is invalid:
1
Error: Mismatched parentheses.
If division by zero occurs:
1
Error: Division by zero.