Day 9 of the 100 Days DSA Challenge: Queues

Welcome to Day 9 of the 100 Days DSA Challenge! Today, we will dive into the concept of queues, a fundamental data structure used in various applications. We will explore different types of queues and their implementations using C language. Let's get started!

1. Implement a Queue Using Arrays

Problem: Implement a queue using arrays with basic operations: enqueue, dequeue, and display.

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

#define MAX 100

int queue[MAX];
int front = -1;
int rear = -1;

void enqueue(int value) {
    if (rear == MAX - 1) {
        printf("Queue overflow\n");
    } else {
        if (front == -1) front = 0;
        queue[++rear] = value;
    }
}

int dequeue() {
    if (front == -1 || front > rear) {
        printf("Queue underflow\n");
        return -1;
    } else {
        return queue[front++];
    }
}

void display() {
    if (front == -1 || front > rear) {
        printf("Queue is empty\n");
    } else {
        for (int i = front; i <= rear; i++) {
            printf("%d ", queue[i]);
        }
        printf("\n");
    }
}

int main() {
    enqueue(10);
    enqueue(20);
    enqueue(30);
    display();
    printf("Dequeued element: %d\n", dequeue());
    display();
    return 0;
}

2. Implement a Circular Queue

Problem: Write a program to implement a circular queue.

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

#define MAX 100

int cqueue[MAX];
int front = -1;
int rear = -1;

void enqueue(int value) {
    if ((front == 0 && rear == MAX - 1) || (rear == (front - 1) % (MAX - 1))) {
        printf("Circular Queue overflow\n");
    } else {
        if (front == -1) {
            front = rear = 0;
        } else if (rear == MAX - 1 && front != 0) {
            rear = 0;
        } else {
            rear++;
        }
        cqueue[rear] = value;
    }
}

int dequeue() {
    if (front == -1) {
        printf("Circular Queue underflow\n");
        return -1;
    }

    int data = cqueue[front];
    if (front == rear) {
        front = rear = -1;
    } else if (front == MAX - 1) {
        front = 0;
    } else {
        front++;
    }
    return data;
}

void display() {
    if (front == -1) {
        printf("Circular Queue is empty\n");
    } else {
        if (rear >= front) {
            for (int i = front; i <= rear; i++) {
                printf("%d ", cqueue[i]);
            }
        } else {
            for (int i = front; i < MAX; i++) {
                printf("%d ", cqueue[i]);
            }
            for (int i = 0; i <= rear; i++) {
                printf("%d ", cqueue[i]);
            }
        }
        printf("\n");
    }
}

int main() {
    enqueue(10);
    enqueue(20);
    enqueue(30);
    display();
    printf("Dequeued element: %d\n", dequeue());
    display();
    return 0;
}

3. First Non-Repeating Character in a Stream of Characters

Problem: Solve the "first non-repeating character in a stream of characters" problem using a queue.

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

#define MAX 256

char queue[MAX];
int front = 0;
int rear = -1;
int charCount[MAX] = {0};

void enqueue(char c) {
    queue[++rear] = c;
}

char dequeue() {
    if (front > rear) {
        return '\0';
    } else {
        return queue[front++];
    }
}

char firstNonRepeating(char str[]) {
    for (int i = 0; i < strlen(str); i++) {
        enqueue(str[i]);
        charCount[str[i]]++;

        while (front <= rear && charCount[queue[front]] > 1) {
            dequeue();
        }
    }

    if (front <= rear) {
        return queue[front];
    } else {
        return '\0';
    }
}

int main() {
    char str[] = "aabcbd";
    char result = firstNonRepeating(str);
    if (result != '\0') {
        printf("First non-repeating character: %c\n", result);
    } else {
        printf("All characters are repeating.\n");
    }
    return 0;
}

4. Implement a Priority Queue Using a Heap

Problem: Implement a priority queue using a heap.

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

#define MAX 100

int heap[MAX];
int heapSize = 0;

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void heapifyUp(int index) {
    int parentIndex = (index - 1) / 2;
    if (parentIndex >= 0 && heap[parentIndex] < heap[index]) {
        swap(&heap[parentIndex], &heap[index]);
        heapifyUp(parentIndex);
    }
}

void heapifyDown(int index) {
    int leftChild = 2 * index + 1;
    int rightChild = 2 * index + 2;
    int largest = index;

    if (leftChild < heapSize && heap[leftChild] > heap[largest]) {
        largest = leftChild;
    }
    if (rightChild < heapSize && heap[rightChild] > heap[largest]) {
        largest = rightChild;
    }
    if (largest != index) {
        swap(&heap[index], &heap[largest]);
        heapifyDown(largest);
    }
}

void enqueue(int value) {
    heap[heapSize] = value;
    heapifyUp(heapSize);
    heapSize++;
}

int dequeue() {
    if (heapSize == 0) {
        printf("Priority Queue underflow\n");
        return -1;
    }

    int root = heap[0];
    heap[0] = heap[--heapSize];
    heapifyDown(0);
    return root;
}

int main() {
    enqueue(10);
    enqueue(20);
    enqueue(30);
    printf("Dequeued element: %d\n", dequeue());
    enqueue(5);
    enqueue(25);
    printf("Dequeued element: %d\n", dequeue());
    return 0;
}

5. Sliding Window Maximum

Problem: Solve the "sliding window maximum" problem using a deque.

#include <stdio.h>

#define MAX 100

int deque[MAX];
int front = -1;
int rear = -1;

void push_back(int value) {
    if (rear == MAX - 1) {
        printf("Deque overflow\n");
    } else {
        if (front == -1) front = 0;
        deque[++rear] = value;
    }
}

void pop_front() {
    if (front == -1 || front > rear) {
        printf("Deque underflow\n");
    } else {
        front++;
    }
}

void pop_back() {
    if (front == -1 || front > rear) {
        printf("Deque underflow\n");
    } else {
        rear--;
    }
}

int get_front() {
    if (front != -1) {
        return deque[front];
    }
    return -1;
}

void slidingWindowMaximum(int arr[], int n, int k) {
    for (int i = 0; i < k; i++) {
        while (rear >= front && arr[i] >= arr[deque[rear]]) {
            pop_back();
        }
        push_back(i);
    }

    for (int i = k; i < n; i++) {
        printf("%d ", arr[get_front()]);

        while (front <= rear && deque[front] <= i - k) {
            pop_front();
        }
        while (rear >= front && arr[i] >= arr[deque[rear]]) {
            pop_back();
        }
        push_back(i);
    }
    printf("%d\n", arr[get_front()]);
}

int main() {
    int arr[] = {1, 3, -1, -3, 5, 3, 6, 7};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 3;
    slidingWindowMaximum(arr, n, k);
    return 0;
}

Conclusion

That wraps up Day 9 of our DSA challenge! We explored various problems related to queues and implemented solutions in C language. Queues are a versatile data structure that can be used in many different scenarios, making them an essential tool in our data structures toolkit. Keep practicing, and you'll become more proficient with queues and other data structures.

Stay tuned for more exciting problems and solutions as we continue to improve our skills in data structures and algorithms.