C Programming Implementing Data Structures Linked Lists Trees Hash Tables Complete Guide

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

Understanding the Core Concepts of C Programming Implementing Data Structures Linked Lists, Trees, Hash Tables

C Programming Implementing Data Structures: Linked Lists, Trees, Hash Tables

Linked Lists

A linked list is a linear data structure where elements (nodes) are not stored at contiguous memory locations but are linked with each other using pointers. Linked lists can be singly linked, doubly linked, or circularly linked.

  • Singly Linked List: Each node contains data and a pointer to the next node. The last node points to NULL.

    struct Node {
        int data;
        struct Node* next;
    };
    
    struct Node* head = NULL; // Global variable pointing to head node
    
  • Doubly Linked List: Each node contains data and two pointers, one to the next node and another to the previous node.

    struct Node {
        int data;
        struct Node* next;
        struct Node* prev;
    };
    
  • Circular Linked List: Similar to singly linked list; the last node points to the first node, forming a circular chain.

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

Key Operations:

  • Insertion: To insert a node, allocate memory, copy data, and adjust pointers.

    void insertAtBeginning(int data) {
        struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->data = data;
        newNode->next = head;
        head = newNode;
    }
    
  • Deletion: To delete a node, traverse list to find node, rearrange pointers, and free memory.

    void deleteNode(int key) {
        struct Node* temp = head;
        struct Node* prev = NULL;
    
        if (temp != NULL && temp->data == key) {
            head = temp->next;
            free(temp);
            return;
        }
    
        while (temp != NULL && temp->data != key) {
            prev = temp;
            temp = temp->next;
        }
    
        if (temp == NULL) return;
    
        prev->next = temp->next;
        free(temp);
    }
    
  • Traversal: Starting from head, visit each node until NULL is encountered.

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

Trees

A tree is a hierarchical data structure with a root node and zero or more child nodes. Each node except the root node is connected with exactly one parent node.

  • Binary Trees: Nodes have at most two children, referred to as left and right child.

    struct Node {
        int data;
        struct Node* left;
        struct Node* right;
    };
    
    struct Node* newNode(int data) {
        struct Node* node = (struct Node*)malloc(sizeof(struct Node));
        node->data = data;
        node->left = NULL;
        node->right = NULL;
        return node;
    }
    
  • Binary Search Trees (BST): A binary tree where the left subtree of a node contains only nodes with keys lesser than the node’s key, and the right subtree only nodes with keys greater.

    struct Node* insert(struct Node* node, int data) {
        if (node == NULL) return newNode(data);
    
        if (data < node->data)
            node->left = insert(node->left, data);
        else if (data > node->data)
            node->right = insert(node->right, data);
    
        return node;
    }
    
  • Balanced Trees: Automatically rebalance to maintain equal height on both sides, like AVL trees or Red-Black trees.

Key Operations:

  • Insertion: Place data in the correct position maintaining BST property.

    struct Node* insert(struct Node* node, int data) {
        if (node == NULL) return newNode(data);
    
        if (data < node->data)
            node->left = insert(node->left, data);
        else if (data > node->data)
            node->right = insert(node->right, data);
    
        return node;
    }
    
  • Deletion: Remove a node by considering three cases: no child, one child, or two children.

    struct Node* deleteNode(struct Node* root, int key) {
        if (root == NULL) return root;
    
        if (key < root->data)
            root->left = deleteNode(root->left, key);
        else if (key > root->data)
            root->right = deleteNode(root->right, key);
        else {
            if (root->left == NULL) {
                struct Node* temp = root->right;
                free(root);
                return temp;
            } else if (root->right == NULL) {
                struct Node* temp = root->left;
                free(root);
                return temp;
            }
    
            struct Node* temp = minValueNode(root->right);
            root->data = temp->data;
            root->right = deleteNode(root->right, temp->data);
        }
        return root;
    }
    
  • Traversal: Use methods like in-order, pre-order, post-order, and level-order to visit all nodes.

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

Hash Tables

A hash table is a data structure used to implement associative arrays. It uses a hash function to compute an index into an array of buckets or slots, from which the desired value can be found.

  • Hash Function: Maps keys to indices to find data efficiently.

    int hashFunction(int key, int capacity) {
        return key % capacity;
    }
    
  • Separate Chaining: If multiple keys map to the same index, use linked lists to store all elements.

    struct Node {
        int key;
        int value;
        struct Node* next;
    };
    
    struct HashTable {
        struct Node** table;
        int capacity;
    };
    
    struct HashTable* createHashTable(int capacity) {
        struct HashTable* ht = (struct HashTable*)malloc(sizeof(struct HashTable));
        ht->capacity = capacity;
        ht->table = (struct Node**)malloc(capacity * sizeof(struct Node*));
        for (int i = 0; i < capacity; i++)
            ht->table[i] = NULL;
        return ht;
    }
    
  • Open Addressing: If a collision occurs, probe other slots until an empty slot is found.

Types of open addressing:

  • Linear Probing: hash(key) + i for i = 0, 1, 2, ...
  • Quadratic Probing: hash(key) + i^2 for i = 0, 1, 2, ...
  • Double Hashing: hash1(key) + i * hash2(key) for i = 0, 1, 2, ...

Key Operations:

  • Insertion: Compute hash, insert key-value pair, handle collisions.

    void insert(struct HashTable* ht, int key, int value) {
        int hash = hashFunction(key, ht->capacity);
        struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
        newNode->key = key;
        newNode->value = value;
        newNode->next = ht->table[hash];
        ht->table[hash] = newNode;
    }
    
  • Search: Compute hash, traverse linked list to find key.

    int search(struct HashTable* ht, int key) {
        int hash = hashFunction(key, ht->capacity);
        struct Node* temp = ht->table[hash];
        while (temp != NULL) {
            if (temp->key == key)
                return temp->value;
            temp = temp->next;
        }
        return -1; // Key not found
    }
    
  • Deletion: Compute hash, find key, remove node.

    void deleteEntry(struct HashTable* ht, int key) {
        int hash = hashFunction(key, ht->capacity);
        struct Node* temp = ht->table[hash];
        struct Node* prev = NULL;
        while (temp != NULL && temp->key != key) {
            prev = temp;
            temp = temp->next;
        }
        if (temp == NULL) return;
        if (prev == NULL)
            ht->table[hash] = temp->next;
        else
            prev->next = temp->next;
        free(temp);
    }
    

Conclusion:

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 Implementing Data Structures Linked Lists, Trees, Hash Tables

1. Linked Lists

Step 1: Define the Node Structure

A linked list is a collection of nodes where each node contains data and a reference (or link) to the next node in the sequence.

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

// Define the structure of a single node in the linked list
struct Node {
    int data;
    struct Node* next;
};

Step 2: Insert a New Node at the Head of the List

// Function to insert a new node at the head of the list
void insertAtHead(struct Node** head, int newData) {
    // Allocate memory for new node
    struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));

    // Assign data to this new node
    newNode->data = newData;

    // Make the next of this new node as head
    newNode->next = (*head);

    // Move the head to point to this new node
    (*head) = newNode;
}

Step 3: Print the Linked List

// Function to print the linked list
void printList(struct Node* node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

Step 4: Complete Example

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

    // Insert nodes at head
    insertAtHead(&head, 2);
    insertAtHead(&head, 4);
    insertAtHead(&head, 6);

    // Print the linked list
    printf("Linked List: ");
    printList(head);

    return 0;
}

2. Trees

Let's create a simple binary search tree (BST).

Step 1: Define the Node Structure

// Define the structure of a single node in the tree
struct TreeNode {
    int data;
    struct TreeNode* left;
    struct TreeNode* right;
};

Step 2: Create a New Node

// Function to create a new tree node
struct TreeNode* createNode(int newData) {
    // Allocate memory for new node
    struct TreeNode* newNode = (struct TreeNode*) malloc(sizeof(struct TreeNode));

    // Assign data to this new node
    newNode->data = newData;
    newNode->left = NULL;
    newNode->right = NULL;

    return newNode;
}

Step 3: Insert a New Node in BST

// Function to insert a new node with given data in BST
struct TreeNode* insertInBST(struct TreeNode* root, int newData) {
    // If the tree is empty, return a new node
    if (root == NULL) return createNode(newData);

    // Otherwise, recur down the tree
    if (newData < root->data)
        root->left = insertInBST(root->left, newData);
    else if (newData > root->data)
        root->right = insertInBST(root->right, newData);

    // Return the (unchanged) node pointer
    return root;
}

Step 4: Print the Tree (In-order Traversal)

// Inorder traversal of BST
void inorderTraversal(struct TreeNode* root) {
    if (root != NULL) {
        inorderTraversal(root->left);
        printf("%d ", root->data);
        inorderTraversal(root->right);
    }
}

Step 5: Complete Example

int main() {
    struct TreeNode* root = NULL;

    root = insertInBST(root, 50);
    insertInBST(root, 30);
    insertInBST(root, 20);
    insertInBST(root, 40);
    insertInBST(root, 70);
    insertInBST(root, 60);
    insertInBST(root, 80);

    printf("Inorder traversal of the BST: ");
    inorderTraversal(root);
    printf("\n");

    return 0;
}

3. Hash Tables

Let's implement a simple hash table using an array of linked lists to handle collisions.

Step 1: Define the Node Structure

Top 10 Interview Questions & Answers on C Programming Implementing Data Structures Linked Lists, Trees, Hash Tables

1. What is a Linked List? How do you create one in C?

Answer: A linked list is a linear data structure where elements, called nodes, contain data and a reference (or link) to the next node in the sequence. In C, a linked list consists of nodes, each represented by a structure containing the data and a pointer to the next node.

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

// Creating a linked list
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;

head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));

head->data = 1;
head->next = second;

second->data = 2;
second->next = third;

third->data = 3;
third->next = NULL;

2. How do you implement a binary search tree in C?

Answer: A binary search tree (BST) is a tree structure where each node has at most two children, referred to as the left child and the right child. The left child node's value must be less than its parent node's value, and the right child node's value must be greater than its parent's.

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

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

struct TreeNode* insert(struct TreeNode* node, int data) {
    if (node == NULL) return newNode(data);

    if (data < node->data)
        node->left = insert(node->left, data);
    else if (data > node->data)
        node->right = insert(node->right, data);

    return node;
}

3. How does one delete a node in a singly linked list?

Answer: To delete a node in a singly linked list, you need to find the previous node of the node to be deleted. Then, update the next pointer of the previous node to skip the node to be deleted and free the memory of the deleted node.

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

    if (temp != NULL && temp->data == key) {
        *head_ref = temp->next;
        free(temp);
        return;
    }

    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if (temp == NULL) return;

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

4. What are the types of binary trees and their characteristics?

Answer:

  • Full Binary Tree: Every node other than the leaves has two children.
  • Complete Binary Tree: All levels are completely filled, except possibly the last, which is filled from left to right.
  • Perfect Binary Tree: All internal nodes have two children, and all leaves are at the same level.
  • Balanced Binary Tree: Heights of the two child subtrees of any node differ by no more than one.

5. Explain the concept of a hash table and its operations in C.

Answer: A hash table is a data structure that implements an associative array, a structure that can map keys to values. Basic operations include insertion, deletion, and lookup.

#define SIZE 100

struct HashItem {
    int key;
    int value;
};

struct HashTable {
    struct HashItem* items[SIZE];
};

unsigned long hash(int key) {
    return key % SIZE;
}

void insert(struct HashTable* table, int key, int value) {
    unsigned long index = hash(key);
    struct HashItem* item = (struct HashItem*)malloc(sizeof(struct HashItem));
    item->key = key;
    item->value = value;
    table->items[index] = item;
}

int search(struct HashTable* table, int key) {
    unsigned long index = hash(key);
    if (table->items[index] == NULL) return -1;
    return table->items[index]->value;
}

6. What is a self-balancing tree? Provide an example.

Answer: A self-balancing binary search tree maintains its balance throughout insertions, deletions, and lookups to allow for O(log n) time complexity for these operations. Examples include AVL trees and Red-Black trees.

struct AVLNode {
    int key;
    struct AVLNode* left;
    struct AVLNode* right;
    int height;
};
// AVL tree implementation involves additional functions like rotations, getBalance etc.

7. How do you implement a linked list that supports insertion and deletion from both ends, i.e., a doubly linked list?

Answer: A doubly linked list consists of nodes that contain data and two pointers: one pointing to the next node and another pointing to the previous node.

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

void append(struct Node** head_ref, int new_data) {
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    struct Node* last = *head_ref;
    new_node->data = new_data;
    new_node->next = NULL;

    if (*head_ref == NULL) {
        new_node->prev = NULL;
        *head_ref = new_node;
        return;
    }

    while (last->next != NULL) last = last->next;
    last->next = new_node;
    new_node->prev = last;
}

void deleteNode(struct Node** head_ref, struct Node* del) {
    if (*head_ref == NULL || del == NULL) return;

    if (*head_ref == del) *head_ref = del->next;

    if (del->next != NULL) del->next->prev = del->prev;

    if (del->prev != NULL) del->prev->next = del->next;

    free(del);
}

8. What is the difference between depth-first search (DFS) and breadth-first search (BFS) in trees?

Answer:

  • Depth-First Search (DFS): Starts at the root and explores as far as possible along each branch before backtracking. It uses a stack (implicit with recursion or explicit with an iterative implementation).
  • Breadth-First Search (BFS): Explores all nodes at the present depth level before moving on to nodes at the next depth level. It uses a queue data structure.

9. What are collision resolution strategies in a hash table?

Answer:

  • Chaining: Each index of the hash table has a linked list of entries that hash to that index.
  • Open Addressing: If there is a collision, the hash table looks for the next empty bucket within the hash table itself.

10. How do you balance an AVL tree during an insertion?

Answer: After inserting a node, check the balance factor (difference in heights of left and right subtrees) and perform rotations to maintain balance:

  • Right Rotation: If the balance factor of a node is greater than 1 and the key to be inserted is smaller than the left child of the node.
  • Left Rotation: If the balance factor of a node is less than -1 and the key to be inserted is greater than the right child of the node.
  • Left-Right Rotation: If the balance factor of a node is greater than 1 and the key to be inserted is greater than the left child of the node.
  • Right-Left Rotation: If the balance factor of a node is less than -1 and the key to be inserted is smaller than the right child of the node.

You May Like This Related .NET Topic

Login to post a comment.