#include <stdio.h>
#include <stdlib.h>
#define MAX 5
typedef struct {
int items[MAX];
int front;
int rear;
} Queue;
// Function to initialize the queue
void initQueue(Queue* q) {
q->front = -1;
q->rear = -1;
}
// Function to check if the queue is empty
int isEmpty(Queue* q) {
return q->front == -1;
}
// Function to check if the queue is full
int isFull(Queue* q) {
return (q->rear + 1) % MAX == q->front;
}
// Function to enqueue an element
void enqueue(Queue* q, int value) {
if (isFull(q)) {
printf(“Queue Overflow! Cannot enqueue %d\n”, value);
return;
}
if (isEmpty(q)) {
q->front = 0; // Set front to 0 if the queue was empty
}
q->rear = (q->rear + 1) % MAX; // Circular increment of rear
q->items[q->rear] = value; // Insert the value at rear
printf(“%d enqueued to queue.\n”, value);
}
// Function to dequeue an element
int dequeue(Queue* q) {
if (isEmpty(q)) {
printf(“Queue Underflow! Cannot dequeue\n”);
return -1; // Return an error value
}
int dequeuedValue = q->items[q->front]; // Retrieve the front element
if (q->front == q->rear) { // The queue will become empty
q->front = -1;
q->rear = -1;
} else {
q->front = (q->front + 1) % MAX; // Circular increment of front
}
printf(“%d dequeued from queue.\n”, dequeuedValue);
return dequeuedValue;
}
// Main function to demonstrate Enqueue and Dequeue
int main() {
Queue q;
initQueue(&q);
enqueue(&q, 10);
enqueue(&q, 20);
enqueue(&q, 30);
dequeue(&q);
dequeue(&q);
return 0;
}
3.4 Linear Queue, Circular Queue, Priority Queue.
Queues are essential data structures that organize data in a specific order, typically following the First In, First Out (FIFO) principle. Different types of queues serve various applications and performance requirements. Here are three common types: Linear Queue, Circular Queue, and Priority Queue.
1. Linear Queue
Definition: A Linear Queue is a straightforward implementation of a queue, where elements are arranged in a linear order. In a linear queue, the first element added is the first one to be removed (FIFO).
Characteristics:
- Structure: Implemented using an array or linked list.
- Fixed Size: If implemented using an array, the size of the queue is fixed.
- Overflow Condition: Occurs when attempting to add an element to a full queue.
- Underflow Condition: Occurs when attempting to remove an element from an empty queue.
Operations:
- Enqueue: Adds an element to the rear of the queue.
- Dequeue: Removes an element from the front of the queue.
Example:
Queue: [1, 2, 3, 4]
Dequeue → Removes 1
Queue: [2, 3, 4]
Enqueue 5 → Adds 5
Queue: [2, 3, 4, 5]
C Implementation:
#define MAX 5
int queue[MAX];
int front = -1;
int rear = -1;
void enqueue(int value) {
if (rear == MAX – 1) {
printf(“Queue Overflow\n”);
return;
}
if (front == -1) {
front = 0; // First element
}
queue[++rear] = value;
}
int dequeue() {
if (front == -1) {
printf(“Queue Underflow\n”);
return -1;
}
int value = queue[front++];
if (front > rear) {
front = rear = -1; // Reset queue
}
return value;
}
2. Circular Queue
Definition: A Circular Queue is an advanced version of a linear queue that efficiently utilizes the available space by connecting the last position back to the first position, thus forming a circle.
Characteristics:
- Circular Structure: The last position points to the first position.
- No Wasted Space: Allows for efficient use of space, especially after multiple enqueue and dequeue operations.
- Wrap Around: The rear and front can wrap around to the beginning of the array when reaching the end.
Operations:
- Enqueue: Adds an element to the rear. The rear pointer wraps around if it reaches the end of the array.
- Dequeue: Removes an element from the front. The front pointer wraps around if it reaches the end of the array.
Example:
Queue: [(priority 2, ‘A’), (priority 1, ‘B’), (priority 3, ‘C’)]
Remove → Removes ‘C’ (highest priority)
Queue: [(priority 2, ‘A’), (priority 1, ‘B’)]
C Implementation:
#define MAX 5
int queue[MAX];
int front = -1;
int rear = -1;
void enqueue(int value) {
if ((rear + 1) % MAX == front) {
printf(“Queue Overflow\n”);
return;
}
if (front == -1) {
front = 0; // First element
}
rear = (rear + 1) % MAX; // Circular increment
queue[rear] = value;
}
int dequeue() {
if (front == -1) {
printf(“Queue Underflow\n”);
return -1;
}
int value = queue[front];
if (front == rear) {
front = rear = -1; // Reset queue
} else {
front = (front + 1) % MAX; // Circular increment
}
return value;
}
3. Priority Queue
Definition: A Priority Queue is a specialized queue where each element has a priority associated with it. Elements are dequeued based on their priority rather than their order in the queue. The element with the highest priority is processed first.
Characteristics:
- Priority Levels: Elements can have different levels of importance. Higher priority elements are dequeued before lower priority ones.
- Dynamic Size: Usually implemented using a dynamic data structure, such as a heap, for efficient access and modification.
- Not FIFO: Unlike standard queues, priority queues do not follow the FIFO principle; they follow priority levels.
Operations:
- Insert: Adds an element to the queue with an associated priority.
- Remove: Removes the element with the highest priority.
Example:
Queue: [(priority 2, ‘A’), (priority 1, ‘B’), (priority 3, ‘C’)]
Remove → Removes ‘C’ (highest priority)
Queue: [(priority 2, ‘A’), (priority 1, ‘B’)]
C Implementation:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int priority;
char data;
} Node;
typedef struct {
Node* arr;
int size;
int capacity;
} PriorityQueue;
void insert(PriorityQueue* pq, char data, int priority) {
if (pq->size == pq->capacity) {
printf(“Queue Overflow\n”);
return;
}
pq->arr[pq->size].data = data;
pq->arr[pq->size].priority = priority;
pq->size++;
// Sort the array based on priority (higher priority first)
for (int i = pq->size – 1; i > 0; i–) {
if (pq->arr[i].priority > pq->arr[i – 1].priority) {
Node temp = pq->arr[i];
pq->arr[i] = pq->arr[i – 1];
pq->arr[i – 1] = temp;
} else {
break;
}
}
}
Node remove(PriorityQueue* pq) {
if (pq->size == 0) {
printf(“Queue Underflow\n”);
return (Node){-1, ‘\0’}; // Return an invalid node
}
return pq->arr[–pq->size]; // Remove the highest priority node
}
Write a program to implement linear and circular queue operations
Here’s a comprehensive implementation of both Linear Queue and Circular Queue operations in C. This program includes functions for enqueueing and dequeueing elements, along with basic menu-driven user interaction for testing these operations.
Linear Queue Implementation
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
typedef struct {
int items[MAX];
int front;
int rear;
} LinearQueue;
// Function to initialize the queue
void initLinearQueue(LinearQueue* q) {
q->front = -1;
q->rear = -1;
}
// Function to check if the linear queue is empty
int isLinearEmpty(LinearQueue* q) {
return q->front == -1;
}
// Function to check if the linear queue is full
int isLinearFull(LinearQueue* q) {
return q->rear == MAX – 1;
}
// Function to enqueue an element into the linear queue
void linearEnqueue(LinearQueue* q, int value) {
if (isLinearFull(q)) {
printf(“Linear Queue Overflow\n”);
return;
}
if (isLinearEmpty(q)) {
q->front = 0; // First element
}
q->items[++q->rear] = value; // Increment rear and add element
printf(“%d enqueued to Linear Queue\n”, value);
}
// Function to dequeue an element from the linear queue
int linearDequeue(LinearQueue* q) {
if (isLinearEmpty(q)) {
printf(“Linear Queue Underflow\n”);
return -1; // Return an error value
}
int value = q->items[q->front++];
if (q->front > q->rear) {
// Reset queue if it becomes empty
q->front = q->rear = -1;
}
printf(“%d dequeued from Linear Queue\n”, value);
return value;
}
// Function to display the linear queue
void displayLinearQueue(LinearQueue* q) {
if (isLinearEmpty(q)) {
printf(“Linear Queue is empty\n”);
return;
}
printf(“Linear Queue: “);
for (int i = q->front; i <= q->rear; i++) {
printf(“%d “, q->items[i]);
}
printf(“\n”);
}
Circular Queue Implementation
typedef struct {
int items[MAX];
int front;
int rear;
} CircularQueue;
// Function to initialize the circular queue
void initCircularQueue(CircularQueue* q) {
q->front = -1;
q->rear = -1;
}
// Function to check if the circular queue is empty
int isCircularEmpty(CircularQueue* q) {
return q->front == -1;
}
// Function to check if the circular queue is full
int isCircularFull(CircularQueue* q) {
return (q->rear + 1) % MAX == q->front;
}
// Function to enqueue an element into the circular queue
void circularEnqueue(CircularQueue* q, int value) {
if (isCircularFull(q)) {
printf(“Circular Queue Overflow\n”);
return;
}
if (isCircularEmpty(q)) {
q->front = 0; // First element
}
q->rear = (q->rear + 1) % MAX; // Circular increment
q->items[q->rear] = value; // Add element
printf(“%d enqueued to Circular Queue\n”, value);
}
// Function to dequeue an element from the circular queue
int circularDequeue(CircularQueue* q) {
if (isCircularEmpty(q)) {
printf(“Circular Queue Underflow\n”);
return -1; // Return an error value
}
int value = q->items[q->front];
if (q->front == q->rear) {
// Reset queue if it becomes empty
q->front = q->rear = -1;
} else {
q->front = (q->front + 1) % MAX; // Circular increment
}
printf(“%d dequeued from Circular Queue\n”, value);
return value;
}
// Function to display the circular queue
void displayCircularQueue(CircularQueue* q) {
if (isCircularEmpty(q)) {
printf(“Circular Queue is empty\n”);
return;
}
printf(“Circular Queue: “);
int i = q->front;
while (1) {
printf(“%d “, q->items[i]);
if (i == q->rear) {
break;
}
i = (i + 1) % MAX; // Circular increment
}
printf(“\n”);
}
Main Program to Test the Queues
int main() {
LinearQueue linearQueue;
CircularQueue circularQueue;
initLinearQueue(&linearQueue);
initCircularQueue(&circularQueue);
int choice, value;
while (1) {
printf(“\n1. Linear Queue Operations\n”);
printf(“2. Circular Queue Operations\n”);
printf(“3. Exit\n”);
printf(“Enter your choice: “);
scanf(“%d”, &choice);
switch (choice) {
case 1: // Linear Queue
printf(“\nLinear Queue Menu:\n”);
printf(“1. Enqueue\n”);
printf(“2. Dequeue\n”);
printf(“3. Display\n”);
printf(“Enter your choice: “);
scanf(“%d”, &choice);
if (choice == 1) {
printf(“Enter value to enqueue: “);
scanf(“%d”, &value);
linearEnqueue(&linearQueue, value);
} else if (choice == 2) {
linearDequeue(&linearQueue);
} else if (choice == 3) {
displayLinearQueue(&linearQueue);
}
break;
case 2: // Circular Queue
printf(“\nCircular Queue Menu:\n”);
printf(“1. Enqueue\n”);
printf(“2. Dequeue\n”);
printf(“3. Display\n”);
printf(“Enter your choice: “);
scanf(“%d”, &choice);
if (choice == 1) {
printf(“Enter value to enqueue: “);
scanf(“%d”, &value);
circularEnqueue(&circularQueue, value);
} else if (choice == 2) {
circularDequeue(&circularQueue);
} else if (choice == 3) {
displayCircularQueue(&circularQueue);
}
break;
case 3:
exit(0);
default:
printf(“Invalid choice. Please try again.\n”);
}
}
return 0;
}
Explanation of the Code
- Linear Queue Implementation:
- Defined using a structure that holds the queue items, front, and rear indices.
- Provides functions for initialization, checking empty/full conditions, enqueueing, dequeuing, and displaying the queue.
- Circular Queue Implementation:
- Similar to the linear queue but includes logic to wrap around the array using modular arithmetic.
- The same functions as the linear queue are implemented for circular operations.
- Main Function:
- Contains a menu-driven interface to test both linear and circular queue operations.
- Allows the user to enqueue, dequeue, and display the contents of the queues.
How to Compile and Run
- Copy the complete code into a
.c
file (e.g., queues.c
).
- Open a terminal and navigate to the directory containing the file.
- Compile the program using:
- Run the program with:
This implementation will allow you to interactively test both linear and circular queue operations.