0% found this document useful (0 votes)
7 views

Data Structures_ Queue to Circular Queue Notes pt01

The document provides a comprehensive guide on queues and circular queues, explaining their definitions, operations, and implementations using arrays. It highlights the limitations of regular queues, particularly regarding space utilization, and introduces circular queues as a solution to these issues. The document includes code examples and visualizations to illustrate the concepts and operations effectively.

Uploaded by

thangenabil44
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Data Structures_ Queue to Circular Queue Notes pt01

The document provides a comprehensive guide on queues and circular queues, explaining their definitions, operations, and implementations using arrays. It highlights the limitations of regular queues, particularly regarding space utilization, and introduces circular queues as a solution to these issues. The document includes code examples and visualizations to illustrate the concepts and operations effectively.

Uploaded by

thangenabil44
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Data Structures: Queue to Circular Queue

Complete Beginner's Guide

III. Queue

📦 Queue as Abstract Data Type (ADT)


Definition: A queue is a linear data structure that follows the First-In-First-Out (FIFO) principle.

Real-life example: Think of people standing in line for movie tickets. The person who came first gets
served first.

Show Image

Basic Operations:

Operation Description

Enqueue Add an element to the rear/back

Dequeue Remove an element from the front

Front Get the front element without removing

IsEmpty Check if queue is empty

IsFull Check if queue is full


 

🔢 Array Implementation of Queue


In this implementation, we will use an array to store queue elements. We'll need to keep track of both the
front and rear indices.
c
#include <stdio.h>

#define MAX 5 // Maximum size of queue

// Global variables
int queue[MAX]; // Array to store queue elements
int front = -1; // Index of front element
int rear = -1; // Index of rear element

// Function to check if queue is full


int isFull() {
if (rear == MAX - 1) { // If rear is at the last index
return 1; // Return true (queue is full)
} else {
return 0; // Return false (queue is not full)
}
}

// Function to check if queue is empty


int isEmpty() {
if (front == -1 || front > rear) { // If front is -1 or has crossed rear
return 1; // Return true (queue is empty)
} else {
return 0; // Return false (queue is not empty)
}
}

// Function to add an element to the queue


void enqueue(int item) {
if (isFull()) { // Check if queue is full
printf("Queue Overflow\n"); // Print error message
} else {
if (front == -1) { // If queue was empty
front = 0; // Set front to the first position
}
rear++; // Increment rear
queue[rear] = item; // Place the item at rear position
printf("%d enqueued to queue\n", item);
}
}

// Function to remove an element from the queue


int dequeue() {
if (isEmpty()) { // Check if queue is empty
printf("Queue Underflow\n"); // Print error message
return -1; // Return error value
} else {
int item = queue[front]; // Get the front item
front++; // Increment front
if (front > rear) { // If the last item was dequeued
front = rear = -1; // Reset front and rear
}
return item; // Return the item
}
}

// Function to get the front element without removing it


int getFront() {
if (isEmpty()) { // Check if queue is empty
printf("Queue is empty\n"); // Print error message
return -1; // Return error value
} else {
return queue[front]; // Return the front item
}
}

// Sample usage
int main() {
enqueue(10); // Add 10 to queue
enqueue(20); // Add 20 to queue
enqueue(30); // Add 30 to queue

printf("Front element: %d\n", getFront()); // Should print 10

printf("Dequeued: %d\n", dequeue()); // Should print 10


printf("Dequeued: %d\n", dequeue()); // Should print 20

printf("Front element after dequeues: %d\n", getFront()); // Should print 30

return 0;
}

Step-by-Step Algorithm Explanation:

1. Initialize the queue:


Create an array of fixed size MAX

Set front and rear to -1 (indicating empty queue)

2. isEmpty() function:
Returns true if front is -1 (queue never started) or front > rear (all elements dequeued)

Otherwise returns false


3. isFull() function:
Returns true if rear == MAX-1 (last position filled)

Otherwise returns false

4. enqueue() function:
Check if queue is full

If full, display overflow message

If not full:
If queue was empty (front == -1), set front to 0

Increment rear

Place the item at rear position

5. dequeue() function:
Check if queue is empty

If empty, display underflow message and return error value

If not empty:
Get the item at front position

Increment front

If front crosses rear (last item dequeued), reset front and rear to -1

Return the item

6. getFront() function:
Check if queue is empty

If empty, display error message and return error value

If not empty, return the item at front position

Memory Visualization:

Let's visualize a queue with MAX = 5 after adding some elements:

After enqueue(10), enqueue(20), enqueue(30):

Array: [10, 20, 30, _, _]


Indices: 0 1 2 3 4
↑ ↑
front rear

After dequeue() (removes 10):


Array: [10, 20, 30, _, _]
Indices: 0 1 2 3 4
↑ ↑
front rear

❓ Q&A for Queue


Q1: What is a Queue?

A: A Queue is a linear data structure that follows the First-In-First-Out (FIFO) principle, meaning the element
that is inserted first will be the first one to be removed.

Q2: What are the main operations of a Queue?

A: The main operations are:

Enqueue: Add an element to the rear of the queue

Dequeue: Remove an element from the front of the queue


Front/Peek: View the front element without removing it
IsEmpty: Check if the queue is empty

IsFull: Check if the queue is full (in case of array implementation)

Q3: What is the difference between Stack and Queue?

A: A Stack follows the Last-In-First-Out (LIFO) principle, where the last element added is the first one to be
removed. A Queue follows the First-In-First-Out (FIFO) principle, where the first element added is the first
one to be removed.

Q4: What are the real-life applications of Queue?

A: Real-life applications include:

Waiting lines at ticket counters, grocery stores, etc.


Print job scheduling in printers

CPU task scheduling


Call center phone systems

Traffic management

Q5: What are the limitations of array implementation of Queue?

A: The main limitations are:

Fixed size (cannot grow dynamically)


Inefficient space utilization (after some dequeue operations, the front moves ahead leaving unused
space at the beginning)

Q6: How can we solve the space utilization problem in Queue?

A: We can solve it by using a Circular Queue implementation, which reuses the space at the beginning after
dequeue operations.

🔄 Problems with Simple Queue


The array implementation of a queue has a significant drawback: inefficient space utilization.

The Problem:

1. As we dequeue elements, the front index moves forward.


2. Even if we dequeue all elements, we cannot add more than MAX - front elements.

3. The space at the beginning of the array (from index 0 to front-1) remains unused.

Illustration:

Initial state:

Array: [10, 20, 30, 40, 50]


Indices: 0 1 2 3 4
↑ ↑
front rear

After dequeue() twice (removing 10 and 20):

Array: [10, 20, 30, 40, 50]


Indices: 0 1 2 3 4
↑ ↑
front rear

Now, if we try to enqueue a new element, we'll get "Queue Overflow" even though there are two unused
spaces at the beginning!

Solution:

1. Reset front and rear to -1 when the queue becomes empty.

2. Use a Circular Queue implementation to reuse the space.

🔄 Circular Queue Concept


A Circular Queue is an enhanced version of a regular queue that solves the problem of inefficient space
utilization.

Definition: A Circular Queue is a linear data structure in which operations are performed based on FIFO
principle and the last position is connected back to the first position to make a circle.

How it works:

1. When we reach the end of the array, we wrap around to the beginning.
2. We use modulo arithmetic ( % ) to implement this circular behavior.

Visualization:

front

[10] [20] [30]
↑ ↑
rear → [50] [40] ← items

In this circular arrangement, after element 50, the next element would be at position 0 (making it circular).

🔢 Array Implementation of Circular Queue


Here's how to implement a Circular Queue using an array:
c
#include <stdio.h>

#define MAX 5 // Maximum size of circular queue

// Global variables
int cqueue[MAX]; // Array to store circular queue elements
int front = -1; // Index of front element
int rear = -1; // Index of rear element

// Function to check if circular queue is full


int isFull() {
if ((front == 0 && rear == MAX - 1) || (front == rear + 1)) {
return 1; // Return true (queue is full)
} else {
return 0; // Return false (queue is not full)
}
}

// Function to check if circular queue is empty


int isEmpty() {
if (front == -1) { // If front is -1
return 1; // Return true (queue is empty)
} else {
return 0; // Return false (queue is not empty)
}
}

// Function to add an element to the circular queue


void enqueue(int item) {
if (isFull()) { // Check if queue is full
printf("Circular Queue Overflow\n"); // Print error message
} else {
if (front == -1) { // If queue was empty
front = 0; // Set front to the first position
}
rear = (rear + 1) % MAX; // Increment rear in circular manner
cqueue[rear] = item; // Place the item at rear position
printf("%d enqueued to circular queue\n", item);
}
}

// Function to remove an element from the circular queue


int dequeue() {
if (isEmpty()) { // Check if queue is empty
printf("Circular Queue Underflow\n"); // Print error message
return -1; // Return error value
} else {
int item = cqueue[front]; // Get the front item
if (front == rear) { // If the last item was dequeued
front = rear = -1; // Reset front and rear
} else {
front = (front + 1) % MAX; // Increment front in circular manner
}
return item; // Return the item
}
}

// Function to get the front element without removing it


int getFront() {
if (isEmpty()) { // Check if queue is empty
printf("Circular Queue is empty\n"); // Print error message
return -1; // Return error value
} else {
return cqueue[front]; // Return the front item
}
}

// Sample usage
int main() {
enqueue(10); // Add 10 to queue
enqueue(20); // Add 20 to queue
enqueue(30); // Add 30 to queue
enqueue(40); // Add 40 to queue

printf("Front element: %d\n", getFront()); // Should print 10

printf("Dequeued: %d\n", dequeue()); // Should print 10


printf("Dequeued: %d\n", dequeue()); // Should print 20

// Now we can add more elements even though the array is "full"
enqueue(50); // Add 50 to queue
enqueue(60); // Add 60 to queue

printf("Front element after changes: %d\n", getFront()); // Should print 30

return 0;
}

Key Differences from Regular Queue:

1. The isFull() condition is different:


A circular queue is full when front == 0 && rear == MAX-1 (regular wraparound hasn't
occurred)

OR when front == rear + 1 (wraparound has occurred)

2. Circular increment using modulo:


rear = (rear + 1) % MAX

front = (front + 1) % MAX

Step-by-Step Algorithm Explanation:

1. Initialize the circular queue:


Create an array of fixed size MAX
Set front and rear to -1 (indicating empty queue)

2. isEmpty() function:
Returns true if front is -1 (queue never started)
Otherwise returns false

3. isFull() function:
Returns true if front is at position 0 AND rear is at last position (MAX-1)

OR if front is exactly one position ahead of rear (wrapped around)


Otherwise returns false

4. enqueue() function:
Check if queue is full

If full, display overflow message

If not full:
If queue was empty (front == -1), set front to 0

Update rear = (rear + 1) % MAX (circular increment)


Place the item at rear position

5. dequeue() function:
Check if queue is empty
If empty, display underflow message and return error value

If not empty:
Get the item at front position

If front equals rear (last item), reset front and rear to -1

Otherwise, update front = (front + 1) % MAX (circular increment)


Return the item

6. getFront() function:
Check if queue is empty
If empty, display error message and return error value

If not empty, return the item at front position

Memory Visualization:

Let's visualize a circular queue with MAX = 5:

Initial state (empty):

Array: [_, _, _, _, _]
Indices: 0 1 2 3 4
front = -1, rear = -1

After enqueue(10), enqueue(20), enqueue(30):

Array: [10, 20, 30, _, _]


Indices: 0 1 2 3 4
↑ ↑
front rear

After dequeue() twice (removes 10, 20):

Array: [10, 20, 30, _, _]


Indices: 0 1 2 3 4

front

rear

After enqueue(40), enqueue(50):

Array: [10, 20, 30, 40, 50]


Indices: 0 1 2 3 4
↑ ↑
front rear

After dequeue() twice (removes 30, 40) and enqueue(60):

Array: [60, 20, 30, 40, 50]


Indices: 0 1 2 3 4
↑ ↑
rear front
Notice how we're reusing the space at index 0!

❓ Q&A for Circular Queue


Q1: What is a Circular Queue?

A: A Circular Queue is a linear data structure that follows the FIFO principle and connects the last position to
the first position to form a circle, allowing better memory utilization by reusing the empty spaces.

Q2: What problem does a Circular Queue solve?

A: Circular Queue solves the problem of inefficient space utilization in a regular queue implementation. In a
regular queue, after dequeuing elements, the space at the beginning cannot be reused without resetting the
entire queue, while a Circular Queue allows reusing those spaces.

Q3: How does a Circular Queue detect if it's full?

A: A Circular Queue is full when:

Front is at position 0 and rear is at the last position (MAX-1), OR

Front is exactly one position ahead of rear (front == rear + 1)

Q4: How does a Circular Queue implement "wrapping around"?

A: Circular Queue implements wrapping around using the modulo operator (%). When incrementing front
or rear, it uses (index + 1) % MAX which makes the index go back to 0 after reaching MAX-1.

Q5: What are the real-life applications of Circular Queue?

A: Real-life applications include:

CPU scheduling

Memory management
Traffic system management

Data streaming (like buffering in media players)


Round-robin scheduling algorithm

Q6: What is the difference between enqueue operation in regular Queue and Circular Queue?

A: In a regular Queue, the enqueue operation simply increments the rear index (rear++), while in a Circular
Queue, it uses modulo arithmetic to wrap around: rear = (rear + 1) % MAX .

Q7: What are the advantages of Circular Queue over regular Queue?

A: Advantages include:
Better memory utilization (reuses empty spaces)
No need to shift elements

Can operate indefinitely within its fixed size


More efficient for applications that require continuous queue operations

Q8: Can a Circular Queue become full even if there are empty spaces?

A: No, that's the main advantage of a Circular Queue. It can detect and utilize any empty spaces, becoming
full only when all spaces are actually occupied.

You might also like