C Programming Data Structures Operations Insertion Deletion Traversal Complete Guide

 Last Update:2025-06-23T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    8 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of C Programming data structures Operations Insertion, Deletion, Traversal


Arrays

Insertion:

In arrays, insertion involves adding an element at a specific position or at the end. Shifting elements to the right to accommodate the new element is necessary if the insertion is not at the end.

Example (Insertion at the end):
#include <stdio.h>

void insertAtEnd(int arr[], int* n, int newElement) {
    if (*n >= 100) { 
        printf("Array is full!\n");
        return;
    }
    arr[*n] = newElement;
    (*n)++;
}

int main() {
    int arr[100] = {1, 2, 3, 4};
    int n = 4; // Size of array
    int newElement = 5;

    insertAtEnd(arr, &n, newElement);

    printf("Array after insertion at the end: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
Important Information:
  • Time Complexity: O(1) for inserting at the end, O(n) for inserting at the beginning or middle.
  • Space Complexity: O(1). No additional space required beyond what the array already has allocated.

Deletion:

Deletion from an array involves removing an element by shifting subsequent elements leftwards.

Example (Deletion from a given index):
#include <stdio.h>

void deleteFromIndex(int arr[], int* n, int index) {
    if (index >= *n || index < 0) {
        printf("Invalid Index!\n");
        return;
    }
    for (int i = index; i < *n - 1; i++) {
        arr[i] = arr[i + 1];
    }
    (*n)--;
}

int main() {
    int arr[100] = {1, 2, 3, 4, 5};
    int n = 5; // Size of array
    int index = 2;

    deleteFromIndex(arr, &n, index);

    printf("Array after deletion from index %d: ", index);
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
Important Information:
  • Time Complexity: O(n) because all elements to the right of the deleted index must be shifted.
  • Space Complexity: O(1).

Traversal:

Traversal in an array involves visiting each element one after another.

Example:
#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int n = 5; 

    printf("Traversing the array:\n");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
Important Information:
  • Time Complexity: O(n) since every element is visited exactly once.
  • Space Complexity: O(1).

Linked Lists

Insertion:

There are three types of insertions in linked lists:

  • Beginning.
  • Specific Position.
  • End.
Example (Insert at Beginning):
#include <stdio.h>
#include <stdlib.h>

struct Node {
    int data;
    struct Node* next;
};

void insertAtBeginning(struct Node** head, int newData) {
    struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
    newNode->data = newData;
    newNode->next = *head;
    *head = newNode;
}

void printList(struct Node* node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

int main() {
    struct Node* head = NULL;

    insertAtBeginning(&head, 6);
    insertAtBeginning(&head, 2);
    insertAtBeginning(&head, 16);

    printList(head); 

    return 0;
}
Important Information:
  • Time Complexity: O(1) for inserting at the beginning, O(n) for inserting at the end.
  • Space Complexity: O(1) for each node added.

Deletion:

Deletion involves removing a node based on its value or position. It includes updating pointers to bypass the deleted node.

Example (Delete node with a specific value):
#include <stdio.h>
#include <stdlib.h>

void deleteNodeByValue(struct Node** head, int key) {
    struct Node* temp = *head;
    struct Node* prev = NULL;

    if (temp != NULL && temp->data == key) { // If head holds the key
        *head = temp->next;
        free(temp);
        return;
    }
    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) { // Key was not present in list
        printf("Value not found!\n");
        return;
    }

    prev->next = temp->next;
    free(temp);
}

int main() {
    struct Node* head = NULL;

    insertAtBeginning(&head, 7);
    insertAtBeginning(&head, 1);
    insertAtBeginning(&head, 3);
    insertAtBeginning(&head, 2);

    printf("Created Linked List: ");
    printList(head);
    deleteNodeByValue(&head, 1);
    printf("Linked List after Deletion of 1: ");
    printList(head);
    return 0;
}
Important Information:
  • Time Complexity: O(n) for deleting a node by value.
  • Space Complexity: O(1).

Traversal:

Traversal involves iterating through the list by moving from the head to the last node.

Example:

PrintList function in the above example.

Important Information:
  • Time Complexity: O(n), where n is the number of elements.
  • Space Complexity: O(1).

Stacks

Insertion (Push):

Push adds an element to the top of the stack.

Example:
#include <stdio.h>
#define MAX 100

int top = -1;
int stack[MAX];

void push(int x) {
    if (top >= MAX - 1) {
        printf("Stack Overflow\n");
        return;
    }
    stack[++top] = x;
}

void printStack() {
    if (top == -1) {
        printf("Stack is empty!\n");
        return;
    }
    for (int i = top; i >= 0; i--)
        printf("%d ", stack[i]);
    printf("\n");
}

int main() {
    push(10);
    push(20);
    push(30);

    printStack();
    return 0;
}
Important Information:
  • Time Complexity: O(1).
  • Space Complexity: O(MAX) when initializing the stack.

Deletion (Pop):

Pop removes an element from the top of the stack.

Example:
void pop() {
    if (top < 0) {
        printf("Stack Underflow\n");
        return;
    }
    printf("%d popped from stack\n", stack[top--]);
}
Important Information:
  • Time Complexity: O(1).

Traversal:

Displaying the elements in the stack from top to bottom.

Important Information:
  • Time Complexity: O(n).

Queues

Queues involve inserting elements at one end and deleting elements from the other end.

Insertion (Enqueue):

Adds an element at the rear of the queue.

Example:
#include <stdio.h>
#define MAX 100

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

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

void printQueue() {
    if (front == -1) {
        printf("Queue is empty!\n");
        return;
    }
    printf("Printing queue:\n");
    for (int i = front; i <= rear; i++) {
        printf("%d ", queue[i]);
    }
    printf("\n");
}
Important Information:
  • Time Complexity: O(1).

Deletion (Dequeue):

Removes an element from the front of the queue.

Example:
void dequeue() {
    if (front > rear || front == -1) {
        printf("Queue is empty!\n");
        return;
    } else {
        printf("%d dequeued from queue\n", queue[front]);
        front++;
    }
}
Important Information:
  • Time Complexity: O(1).

Traversal:

Iterate through the queue from front to rear.

Important Information:
  • Time Complexity: O(n).

Trees

For binary search trees, we perform different types of insertions and deletions.

Insertion:

Insert a node as per BST rules: smaller values go to the left, larger values to the right.

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

struct TNode {
    int data;
    struct TNode* left, *right;
};

struct TNode* newNode(int data) {
    struct TNode* node = (struct TNode*)malloc(sizeof(struct TNode));
    node->data = data;
    node->left = node->right = NULL;
    return node;
}

struct TNode* insert(struct TNode* root, int data) {
    if (root == NULL) {
        return newNode(data);
    }
    if (data < root->data)
        root->left = insert(root->left, data);
    else
        root->right = insert(root->right, data);
    return root;
}
Important Information:
  • Time Complexity: O(h), where h is the height of the tree.

Deletion:

Remove a node based on value. Handle three cases: no children, one child, two children.

Example:
struct TNode* minValueNode(struct TNode* node) {
    struct TNode* current = node;
    while (current && current->left != NULL)
        current = current->left;
    return current;
}

struct TNode* deleteNode(struct TNode* root, int data) {
    if (root == NULL)
        return root;
    if (data < root->data)
        root->left = deleteNode(root->left, data);
    else if (data > root->data)
        root->right = deleteNode(root->right, data);
    else {
        if (root->left == NULL) {
            struct TNode* temp = root->right;
            free(root);
            return temp;
        } else if (root->right == NULL) {
            struct TNode* temp = root->left;
            free(root);
            return temp;
        }

        struct TNode* temp = minValueNode(root->right);
        root->data = temp->data;
        root->right = deleteNode(root->right, temp->data);
    }
    return root;
}
Important Information:
  • Time Complexity: O(h), where h is the height of the tree.

Traversal:

Visit nodes in a systematic manner: Inorder, Preorder, Postorder.

Example (Inorder Traversal):
void inorder(struct TNode* root) {
    if (root != NULL) {
        inorder(root->left);
        printf("%d ", root->data);
        inorder(root->right);
    }
}
Important Information:
  • Time Complexity: O(n), where n is the number of nodes.
  • Space Complexity: O(h) due to recursive call stack.

Graphs

Graphs can be represented using adjacency lists or matrices.

Insertion:

Adding an edge between two nodes.

Example (Adjacency List Representation):
#include <stdio.h>
#include <stdlib.h>

struct AdjListNode {
    int dest;
    struct AdjListNode* next;
};

struct AdjList {
    struct AdjListNode* head;
};

struct Graph {
    int V;
    struct AdjList* array;
};

struct AdjListNode* newAdjListNode(int dest) {
    struct AdjListNode* newNode = 
     (struct AdjListNode*) malloc(sizeof(struct AdjListNode));
    newNode->dest = dest;
    newNode->next = NULL;
    return newNode;
}

struct Graph* createGraph(int V) {
    struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
    graph->V = V;

    graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));

    for (int i = 0; i < V; ++i)
        graph->array[i].head = NULL;

    return graph;
}

void addEdge(struct Graph* graph, int src, int dest) {
    struct AdjListNode* newNode = newAdjListNode(dest);
    newNode->next = graph->array[src].head;
    graph->array[src].head = newNode;

    newNode = newAdjListNode(src);
    newNode->next = graph->array[dest].head;
    graph->array[dest].head = newNode;
}

void printGraph(struct Graph* graph) {
    for (int v = 0; v < graph->V; ++v) {
        struct AdjListNode* pCrawl = graph->array[v].head;
        printf("Adjacency list of vertex %d\n head ", v);
        while (pCrawl) {
            printf("-> %d", pCrawl->dest);
            pCrawl = pCrawl->next;
        }
        printf("\n");
    }
}
Important Information:
  • Time Complexity: O(1) for adding an edge in an adjacency list.

Deletion:

Removing an edge between two nodes.

Example:
// Function to delete an edge
void deleteEdge(struct Graph* graph, int src, int dest) {
    struct AdjListNode* temp = graph->array[src].head;
    struct AdjListNode* prev = NULL;

    // Traverse adjacency list of src to find and delete destination 
    while (temp && temp->dest != dest) {
        prev = temp;
        temp = temp->next;
    }
    if (temp) { 
        if (prev) {
            prev->next = temp->next;
        } else {
            graph->array[src].head = temp->next;
        }

        free(temp);
    }

    // Traverse adjacency list of dest to find and delete source
    temp = graph->array[dest].head;
    prev = NULL;

    while (temp && temp->dest != src) {
        prev = temp;
        temp = temp->next;
    }
    if (temp) {
        if (prev) {
            prev->next = temp->next;
        } else {
            graph->array[dest].head = temp->next;
        }

        free(temp);
    }
}
Important Information:
  • Time Complexity: O(E/V), where E is edges and V is vertices.

Traversal:

Common methods are Depth First Search (DFS) and Breadth First Search (BFS).

Example (DFS):

Use a recursive helper function.

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement C Programming data structures Operations Insertion, Deletion, Traversal

Introduction to Singly Linked List

A Singly Linked List is a collection of nodes where each node contains data and a reference (or pointer) to the next node in the sequence. The last node points to NULL.

Step-by-Step Example

1. Define the Node Structure

First, we define a structure for the node.

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

// Define the structure for a node in the linked list
struct Node {
    int data;            // Data part
    struct Node* next;   // Pointer to the next node
};

2. Function to Create a New Node

We'll write a function that creates a new node and initializes it.

// Function to create a new node
struct Node* createNode(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        return NULL;
    }
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

3. Insertion Operations

Let's write functions to insert nodes at the beginning, end, and at a specific position.

a. Insert at the Beginning

// Function to insert a node at the beginning of the list
void insertAtBeginning(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (newNode == NULL) return;
    
    newNode->next = *head;
    *head = newNode;
    printf("Inserted %d at the beginning\n", data);
}

b. Insert at the End

// Function to insert a node at the end of the list
void insertAtEnd(struct Node** head, int data) {
    struct Node* newNode = createNode(data);
    if (newNode == NULL) return;
    
    if (*head == NULL) {
        *head = newNode;
    } else {
        struct Node* temp = *head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
    printf("Inserted %d at the end\n", data);
}

c. Insert at a Specific Position

// Function to insert a node at a specific position
void insertAtPosition(struct Node** head, int data, int position) {
    if (position < 1) {
        printf("Invalid position\n");
        return;
    }
    
    if (position == 1) {
        insertAtBeginning(head, data);
        return;
    }
    
    struct Node* newNode = createNode(data);
    if (newNode == NULL) return;

    struct Node* temp = *head;
    int count = 1;
    while (temp != NULL && count < position - 1) {
        temp = temp->next;
        count++;
    }
    
    if (temp == NULL) {
        printf("Position exceeds the length of the list\n");
        free(newNode);
    } else {
        newNode->next = temp->next;
        temp->next = newNode;
        printf("Inserted %d at position %d\n", data, position);
    }
}

4. Deletion Operations

Let's write functions to delete nodes from the beginning, end, and at a specific position.

a. Delete from the Beginning

// Function to delete a node from the beginning of the list
void deleteFromBeginning(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    
    struct Node* temp = *head;
    *head = (*head)->next;
    printf("Deleted %d from the beginning\n", temp->data);
    free(temp);
}

b. Delete from the End

// Function to delete a node from the end of the list
void deleteFromEnd(struct Node** head) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    
    if ((*head)->next == NULL) {
        // If there's only one node
        printf("Deleted %d from the end\n", (*head)->data);
        free(*head);
        *head = NULL;
        return;
    }
    
    struct Node* prev = *head;
    struct Node* temp = (*head)->next;
    while (temp->next != NULL) {
        prev = temp;
        temp = temp->next;
    }
    prev->next = NULL;
    printf("Deleted %d from the end\n", temp->data);
    free(temp);
}

c. Delete from a Specific Position

// Function to delete a node from a specific position
void deleteFromPosition(struct Node** head, int position) {
    if (*head == NULL) {
        printf("List is empty\n");
        return;
    }
    if (position < 1) {
        printf("Invalid position\n");
        return;
    }
    
    if (position == 1) {
        deleteFromBeginning(head);
        return;
    }
    
    struct Node* prev = NULL;
    struct Node* temp = *head;
    int count = 1;
    while (temp != NULL && count < position) {
        prev = temp;
        temp = temp->next;
        count++;
    }
    
    if (temp == NULL) {
        printf("Position exceeds the length of the list\n");
    } else {
        prev->next = temp->next;
        printf("Deleted %d from position %d\n", temp->data, position);
        free(temp);
    }
}

5. Traversal Operation

Let's write a function to print all nodes in the list.

// Function to traverse the list and print its elements
void traverseList(struct Node* head) {
    if (head == NULL) {
        printf("List is empty\n");
        return;
    }
    
    printf("List elements: ");
    struct Node* temp = head;
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}

6. Putting It All Together

Now, let's write the main function to test all of these operations.

Top 10 Interview Questions & Answers on C Programming data structures Operations Insertion, Deletion, Traversal

1. What are the basic data structures used in C Programming?

Answer: In C Programming, the fundamental data structures include arrays, linked lists, stacks, queues, trees, and graphs. Each serves different purposes and has unique insertion, deletion, and traversal characteristics.

2. How do you insert a new element in a dynamically allocated array?

Answer: Inserting an element in a dynamic array involves resizing the array and shifting existing elements. Here’s a brief example:

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

void insertElement(int* arr, int* size, int element, int position) {
    (*size)++;
    arr = (int*)realloc(arr, (*size) * sizeof(int));
    for (int i = *size - 1; i > position; i--) {
        arr[i] = arr[i - 1];
    }
    arr[position] = element;
}

int main() {
    int *arr = (int*)malloc(3 * sizeof(int));
    arr[0] = 1; arr[1] = 2; arr[2] = 3;
    int size = 3;

    insertElement(arr, &size, 10, 1); // Insert 10 at position 1

    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]); // Output: 1 10 2 3
    }

    free(arr);
    return 0;
}

3. Explain how to insert a node in a singly linked list.

Answer: Insertion in a singly linked list can be done at the beginning, end, or a specific position. Here’s how to insert a node at the end:

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

struct Node {
    int data;
    struct Node* next;
};

void insertAtEnd(struct Node** head, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;

    if (*head == NULL) {
        *head = newNode;
        return;
    }

    struct Node* temp = *head;
    while (temp->next != NULL) {
        temp = temp->next;
    }
    temp->next = newNode;
}

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

int main() {
    struct Node* head = NULL;
    insertAtEnd(&head, 1);
    insertAtEnd(&head, 2);
    printList(head); // Output: 1 -> 2 -> NULL

    return 0;
}

4. What is the difference between insertion at the beginning and end of a doubly linked list?

Answer: In a doubly linked list, insertion at the beginning involves:

  • Creating a new node.
  • Setting its next to the current head.
  • Updating the prev of the current head to the new node.
  • Updating the head to point to the new node.

Insertion at the end involves:

  • Creating a new node.
  • Setting its prev to the current tail.
  • Updating the next of the current tail to the new node.
  • Updating the tail to point to the new node.

5. How do you delete a node from a singly linked list given a key?

Answer: Deleting a node involves locating the node by key, adjusting pointers, and freeing memory:

void deleteNode(struct Node** head_ref, int key) {
    struct Node *temp = *head_ref, *prev = NULL;

    // If head node itself holds the key to be deleted
    if (temp != NULL && temp->data == key) {
        *head_ref = temp->next; // Changed head
        free(temp);             // Free old head
        return;
    }

    // Search for the key to be deleted, keep track of the previous node
    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    // If key was not present in linked list
    if (temp == NULL) return;

    // Unlink the node from linked list
    prev->next = temp->next;

    free(temp); // Free memory
}

6. How do you perform a depth-first traversal of a tree in C?

Answer: Depth-first search (DFS) can be implemented using recursion or a stack. Here’s a recursive approach for a binary tree:

void inOrderTraversal(struct Node* root) {
    if (root != NULL) {
        inOrderTraversal(root->left);
        printf("%d ", root->data);
        inOrderTraversal(root->right);
    }
}

7. What’s the difference between pre-order and post-order traversal?

Answer: In a tree:

  • Pre-order visits the root node first, then recursively visits the left subtree, followed by the right subtree.
  • Post-order visits all nodes in the left subtree, then the right subtree, and finally the root node.

8. How do you perform a level-order traversal of a binary tree?

Answer: Level-order traversal, also known as breadth-first traversal, is typically implemented using a queue:

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

struct Node {
    int data;
    struct Node* left;
    struct Node* right;
};

// Function to enqueue a node
void enqueue(struct Node** queue, int* rear, struct Node* new_node) {
    queue[(*rear)++] = new_node;
}

// Function to dequeue a node
struct Node* dequeue(struct Node** queue, int* front) {
    return queue[(*front)++];
}

void levelOrderTraversal(struct Node* root) {
    struct Node* queue[100];
    int front = 0, rear = 0;

    enqueue(queue, &rear, root);
    while (front != rear) {
        struct Node* node = dequeue(queue, &front);
        printf("%d ", node->data);

        if (node->left != NULL) enqueue(queue, &rear, node->left);
        if (node->right != NULL) enqueue(queue, &rear, node->right);
    }
}

9. What is the difference between stack-based and queue-based traversal?

Answer:

  • Stack-based (Depth-First Search - DFS): Uses a stack data structure, where elements are processed last-in, first-out (LIFO). It can explore as deep into a branch as possible before backtracking.
  • Queue-based (Breadth-First Search - BFS): Uses a queue data structure, where elements are processed first-in, first-out (FIFO). It explores all neighbors at the present "depth" prior to moving on to nodes at the next depth level.

10. How do you handle deletion in a binary search tree (BST)?

Answer: Deleting from a BST involves:

  • Key not present: No change.
  • No child (leaf node): Simply remove it.
  • One child: Bypass the node to be deleted to its child.
  • Two children: Find the minimum element in the right subtree (in-order successor), copy its value to the node to be deleted, and delete the in-order successor.

Here’s an example of how to handle the two-children case:

You May Like This Related .NET Topic

Login to post a comment.