#include <stdio.h>
#include <stdlib.h>

// Structure to represent a node in the queue
struct Node {
    int data;
    struct Node* next;
};

// Structure to represent the queue with pointers to the front and rear
struct Queue {
    struct Node *front, *rear;
};

// Function to create a new node with the given data
struct Node* newNode(int data) {
    struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
    temp->data = data;
    temp->next = NULL;
    return temp;
}

// Function to create an empty queue
struct Queue* createQueue() {
    struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
    q->front = q->rear = NULL;
    return q;
}

// Function to add an element to the queue
void enqueue(struct Queue* q, int data) {
    // Create a new node
    struct Node* temp = newNode(data);
    
    // If the queue is empty, the new node will be the front and rear
    if (q->rear == NULL) {
        q->front = q->rear = temp;
        printf("Enqueued %d to the queue.\n", data);
        return;
    }

    // Attach the new node at the end of the queue and change the rear
    q->rear->next = temp;
    q->rear = temp;
    printf("Enqueued %d to the queue.\n", data);
}

// Function to remove an element from the queue
void dequeue(struct Queue* q) {
    // If the queue is empty, there is nothing to dequeue
    if (q->front == NULL) {
        printf("Queue is empty, nothing to dequeue.\n");
        return;
    }

    // Store the previous front and move the front one node ahead
    struct Node* temp = q->front;
    q->front = q->front->next;

    // If the front becomes NULL, then the queue is empty, so set rear to NULL
    if (q->front == NULL) {
        q->rear = NULL;
    }

    printf("Dequeued %d from the queue.\n", temp->data);
    free(temp);
}

// Function to display the current elements of the queue
void displayQueue(struct Queue* q) {
    struct Node* temp = q->front;
    if (temp == NULL) {
        printf("Queue is empty.\n");
        return;
    }

    printf("Queue elements: ");
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}

// Main function to demonstrate queue operations
int main() {
    struct Queue* q = createQueue();

    enqueue(q, 10);
    enqueue(q, 20);
    enqueue(q, 30);

    displayQueue(q);

    dequeue(q);
    displayQueue(q);

    dequeue(q);
    dequeue(q);
    dequeue(q);

    return 0;
}

Explanation:

  1. Data Structure Design:
    • The Node structure represents a node in the linked list, containing data (to store the integer value) and next (a pointer to the next node).
    • The Queue structure has two pointers: front (points to the front of the queue) and rear (points to the end of the queue).
  2. Node Creation:
    • newNode(int data): This function creates a new node using malloc and initializes it with the provided data. It returns a pointer to the newly created node.
  3. Queue Initialization:
    • createQueue(): This function initializes a new Queue by allocating memory for it and setting both front and rear pointers to NULL, indicating an empty queue.
  4. Enqueue Operation:
    • enqueue(struct Queue* q, int data):
      • A new node is created.
      • If the rear is NULL, it means the queue is empty, so both front and rear pointers are set to this new node.
      • Otherwise, the next pointer of the current rear is updated to the new node, and then rear is updated to this new node.
  5. Dequeue Operation:
    • dequeue(struct Queue* q):
      • If the front is NULL, the queue is empty, so a message is printed.
      • Otherwise, the front node is removed, and the front pointer is updated to the next node in the queue.
      • If the queue becomes empty after the removal (i.e., front becomes NULL), then rear is also set to NULL.
  6. Display Function:
    • displayQueue(struct Queue* q): It traverses from front to rear and prints each node’s data.
  7. Main Function:
    • Creates an empty queue.
    • Enqueues elements 10, 20, and 30.
    • Displays the queue.
    • Dequeues elements one by one and displays the queue after each operation.
Enqueued 10 to the queue.
Enqueued 20 to the queue.
Enqueued 30 to the queue.
Queue elements: 10 20 30 
Dequeued 10 from the queue.
Queue elements: 20 30 
Dequeued 20 from the queue.
Dequeued 30 from the queue.
Queue is empty, nothing to dequeue.

Explanation of the Output:

  1. The elements 10, 20, and 30 are added to the queue. After enqueueing, the queue looks like 10 -> 20 -> 30.
  2. The first dequeue operation removes 10, leaving 20 -> 30.
  3. The next dequeue removes 20, leaving only 30.
  4. After removing 30, the queue becomes empty.
  5. Trying to dequeue from an empty queue gives a message indicating that there is nothing to remove.

This implementation demonstrates how to use a linked list to efficiently manage a queue, ensuring that elements can be added or removed dynamically as needed.

Leave a Reply

Your email address will not be published. Required fields are marked *

Verified by MonsterInsights