ProductPromotion
Logo

C Programming

made by https://0x3d.site

Data Structures in C: Linked Lists, Stacks, and Queues
Data structures are fundamental concepts in programming that allow you to organize and manage data efficiently. In C programming, mastering data structures like linked lists, stacks, and queues is crucial for solving complex problems and optimizing code. This guide will delve into these essential data structures, providing both theoretical explanations and practical coding examples.
2024-09-12

Data Structures in C: Linked Lists, Stacks, and Queues

Introduction to Data Structures: What They Are and Why They Matter

Data Structures are ways to store and organize data in a computer so that it can be accessed and modified efficiently. They are crucial for various reasons:

  1. Efficiency: Proper data structures can significantly improve the efficiency of data operations like insertion, deletion, and searching.
  2. Performance: Different data structures have different performance characteristics, making them suitable for specific tasks.
  3. Organization: They help in organizing data logically, making it easier to understand and manipulate.

Understanding data structures helps in making informed decisions about which structure to use based on the problem requirements and constraints.

Implementing a Singly Linked List from Scratch

A singly linked list is a linear data structure where each element (node) contains a value and a pointer to the next node in the sequence. It allows for efficient insertion and deletion operations.

1. Definition of a Node

First, define the structure of a node in the linked list:

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

// Definition of a node in the linked list
typedef struct Node {
    int data;
    struct Node *next;
} Node;

2. Creating a New Node

A function to create a new node:

Node* createNode(int data) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

3. Inserting at the Beginning

Insert a node at the beginning of the linked list:

void insertAtBeginning(Node **head, int data) {
    Node *newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

4. Inserting at the End

Insert a node at the end of the linked list:

void insertAtEnd(Node **head, int data) {
    Node *newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
    } else {
        Node *temp = *head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

5. Displaying the List

Function to display the linked list:

void displayList(Node *head) {
    Node *temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

6. Deleting a Node

Function to delete a node by value:

void deleteNode(Node **head, int data) {
    Node *temp = *head, *prev = NULL;
    if (temp != NULL && temp->data == data) {
        *head = temp->next;
        free(temp);
        return;
    }
    while (temp != NULL && temp->data != data) {
        prev = temp;
        temp = temp->next;
    }
    if (temp == NULL) return;
    prev->next = temp->next;
    free(temp);
}

Building a Stack and a Queue Using Arrays and Pointers

Stacks and queues are abstract data types that are implemented using arrays or linked lists. They have different operational characteristics:

  • Stack: Follows Last-In-First-Out (LIFO) principle.
  • Queue: Follows First-In-First-Out (FIFO) principle.

1. Stack Implementation Using Arrays

A stack supports operations like push (insert) and pop (remove).

Structure Definition:

#define MAX 100

typedef struct {
    int arr[MAX];
    int top;
} Stack;

Initialize Stack:

void initializeStack(Stack *s) {
    s->top = -1;
}

Push Operation:

void push(Stack *s, int value) {
    if (s->top == MAX - 1) {
        printf("Stack Overflow\n");
        return;
    }
    s->arr[++(s->top)] = value;
}

Pop Operation:

int pop(Stack *s) {
    if (s->top == -1) {
        printf("Stack Underflow\n");
        return -1;
    }
    return s->arr[(s->top)--];
}

Peek Operation:

int peek(Stack *s) {
    if (s->top == -1) {
        printf("Stack is Empty\n");
        return -1;
    }
    return s->arr[s->top];
}

2. Stack Implementation Using Linked List

Node Definition:

typedef struct StackNode {
    int data;
    struct StackNode *next;
} StackNode;

Push Operation:

void push(StackNode **top, int value) {
    StackNode *newNode = (StackNode*)malloc(sizeof(StackNode));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->data = value;
    newNode->next = *top;
    *top = newNode;
}

Pop Operation:

int pop(StackNode **top) {
    if (*top == NULL) {
        printf("Stack Underflow\n");
        return -1;
    }
    StackNode *temp = *top;
    int value = temp->data;
    *top = temp->next;
    free(temp);
    return value;
}

Peek Operation:

int peek(StackNode *top) {
    if (top == NULL) {
        printf("Stack is Empty\n");
        return -1;
    }
    return top->data;
}

3. Queue Implementation Using Arrays

A queue supports operations like enqueue (insert) and dequeue (remove).

Structure Definition:

#define MAX 100

typedef struct {
    int arr[MAX];
    int front, rear, size;
} Queue;

Initialize Queue:

void initializeQueue(Queue *q) {
    q->front = 0;
    q->rear = -1;
    q->size = 0;
}

Enqueue Operation:

void enqueue(Queue *q, int value) {
    if (q->size == MAX) {
        printf("Queue Overflow\n");
        return;
    }
    q->rear = (q->rear + 1) % MAX;
    q->arr[q->rear] = value;
    q->size++;
}

Dequeue Operation:

int dequeue(Queue *q) {
    if (q->size == 0) {
        printf("Queue Underflow\n");
        return -1;
    }
    int value = q->arr[q->front];
    q->front = (q->front + 1) % MAX;
    q->size--;
    return value;
}

Peek Operation:

int peek(Queue *q) {
    if (q->size == 0) {
        printf("Queue is Empty\n");
        return -1;
    }
    return q->arr[q->front];
}

4. Queue Implementation Using Linked List

Node Definition:

typedef struct QueueNode {
    int data;
    struct QueueNode *next;
} QueueNode;

Enqueue Operation:

void enqueue(QueueNode **front, QueueNode **rear, int value) {
    QueueNode *newNode = (QueueNode*)malloc(sizeof(QueueNode));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->data = value;
    newNode->next = NULL;
    if (*rear != NULL) {
        (*rear)->next = newNode;
    }
    *rear = newNode;
    if (*front == NULL) {
        *front = *rear;
    }
}

Dequeue Operation:

int dequeue(QueueNode **front, QueueNode **rear) {
    if (*front == NULL) {
        printf("Queue Underflow\n");
        return -1;
    }
    QueueNode *temp = *front;
    int value = temp->data;
    *front = (*front)->next;
    if (*front == NULL) {
        *rear = NULL;
    }
    free(temp);
    return value;
}

Peek Operation:

int peek(QueueNode *front) {
    if (front == NULL) {
        printf("Queue is Empty\n");
        return -1;
    }
    return front->data;
}

Example: A C Program That Uses Stacks for Expression Evaluation

Stacks are commonly used for evaluating mathematical expressions, such as infix expressions, which are converted to postfix notation for easier evaluation.

Postfix Expression Evaluation Example:

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

#define MAX 100

typedef struct {
    int arr[MAX];
    int top;
} Stack;

void initializeStack(Stack *s) {
    s->top = -1;
}

void push(Stack *s, int value) {
    if (s->top == MAX - 1) {
        printf("Stack Overflow\n");
        return;
    }
    s->arr[++(s->top)] = value;
}

int pop(Stack *s) {
    if (s->top == -1) {
        printf("Stack Underflow\n");
        return -1;
    }
    return s->arr[(s->top)--];
}

int evaluatePostfix(const char *expression) {
    Stack s;
    initializeStack(&s);
    int i = 0;
    while (expression[i] != '\0') {
        if (isdigit(expression[i])) {
            push(&s, expression[i] - '0');
        } else {
            int operand2 = pop(&s);
            int operand1 = pop(&s);
            switch (expression[i]) {
                case '+': push(&s, operand1 + operand2); break;
                case '-': push(&s, operand1 - operand2); break;
                case '*': push(&s, operand1 * operand2); break;
                case '/': push(&s, operand1 / operand2); break;
            }
        }
        i++;
    }
    return pop(&s);
}

int main() {
    const char *expression = "231*+9-";
    printf("Postfix Expression Result: %d\n", evaluatePostfix(expression));
    return 0;
}

Best Practices for Choosing the Right Data Structure in C Programming

Selecting the appropriate data structure depends on the specific requirements and constraints of your application. Here are some guidelines:

  1. Understand the Problem: Analyze the operations you need to perform (e.g., search, insert, delete) and choose a data structure that supports these operations efficiently.

  2. Consider Time Complexity: Different data structures have different time complexities for operations. For example, linked lists have O(1) time complexity for insertions/deletions at the beginning but O(n) for accessing elements, whereas arrays offer O(1) access but O(n) insertions/deletions.

  3. Memory Usage: Consider the memory overhead associated with different data structures. For instance, linked lists use extra memory for pointers, whereas arrays have a fixed size and do not have this overhead.

  4. Dynamic vs. Static: Use dynamic data structures like linked lists when the size of the data is unknown or can change frequently. Use static data structures like arrays when the size is fixed and known beforehand.

  5. Algorithm Requirements: Some algorithms are inherently tied to specific data structures. For example, depth-first search (DFS) uses stacks, while breadth-first search (BFS) uses queues.

  6. Implementation Complexity: Evaluate the complexity of implementing and maintaining a data structure. Some data structures, like balanced trees, may offer better performance but are more complex to implement.

Conclusion

Mastering data structures such as linked lists, stacks, and queues is crucial for effective C programming. By understanding their theoretical underpinnings and practical implementations, you can optimize your programs and solve complex problems more efficiently. Practice implementing these structures and apply them to real-world scenarios to deepen your understanding and proficiency. Happy coding!

Articles
to learn more about the c-programming concepts.

More Resources
to gain others perspective for more creation.

mail [email protected] to add your project or resources here 🔥.

FAQ's
to learn more about C Programming.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory