× back Advantages of linked lists over array. Drawbacks of linked lists Applications of linked list Types of linked list Singly linked list Doubly linked list Garbage collection and compaction
Next Topic → ← Previous Topic

Linked list

Advantages of Linked Lists over array:

Drawbacks of linked lists:

Applications of linked list:

Types of Linked Lists:

Singly linked list

Syntax of a node ↓

                
struct node 
{
    int data;
    struct node *next;
};
                
            
                
struct node *start = NULL; // points to the first element. Initially NULL
                
            

Operations on singly linked list ↓

Insertion are of three types ↓

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

typedef struct node
{
    int data;
    struct node *next;
} node;
node *start = NULL;

void insertAtFront();
void insertAtBack();
void insertAfterNode();
void deleteAtFront();
void deleteAtBack();
void deleteANode();
void display();

int main()
{
    int choice;
    while (1)
    {
        printf("\n------- MENU ---------");
        printf("\n1. Insert at front");
        printf("\n2. Insert at back");
        printf("\n3. Insert after a node");
        printf("\n4. Delete at front");
        printf("\n5. Delete at back");
        printf("\n6. Delete a node");
        printf("\n7. Display");
        printf("\n8. Exit");
        printf("\nEnter you choice : ");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            insertAtFront();
            break;
        case 2:
            insertAtBack();
            break;
        case 3:
            insertAfterNode();
            break;
        case 4:
            deleteAtFront();
            break;
        case 5:
            deleteAtBack();
            break;
        case 6:
            deleteANode();
            break;
        case 7:
            display();
            break;
        case 8:
            exit(0);
        default:
            printf("\nEnter a correct choice");
        }
    }
    return 0;
}
void insertAtFront()
{
    node *newnode = (node *)malloc(sizeof(node));
    printf("Enter a value : ");
    scanf("%d", &newnode->data);
    newnode->next = start;
    start = newnode;
}

void insertAtBack()
{
    node *newnode = (node *)malloc(sizeof(node));
    node *last = start;
    printf("Enter a value : ");
    scanf("%d", &newnode->data);
    newnode->next = NULL;
    if (start == NULL)
        start = newnode;
    else
    {
        while (last->next != NULL)
            last = last->next;
        last->next = newnode;
    }
}

void insertAfterNode()
{
    if (start == NULL)
    {
        printf("\nList is empty cannot insert after a node\n");
        return;
    }
    int node_val;
    printf("\nEnter a node value after which you want to insert : ");
    scanf("%d", &node_val);
    node *ptr = start;
    while (ptr->data != node_val)
    {
        if (ptr->next == NULL)
        {
            printf("\n Node not found cannot insert element");
            return;
        }
        ptr = ptr->next;
    }
    node *newNode = (node *)malloc(sizeof(node));
    newNode->next = NULL;
    printf("\nEnter the value : ");
    scanf("%d", &newNode->data);
    newNode->next = ptr->next;
    ptr->next = newNode;
}

void deleteAtFront()
{
    if (start == NULL)
    {
        printf("\nList is empty");
        return;
    }
    node *temp = start;
    start = start->next;
    free(temp);
}

void deleteAtBack()
{
    if (start == NULL)
    {
        printf("\nList is empty");
        return;
    }
    if (start->next == NULL)
    {
        free(start);
        start = NULL;
        return;
    }
    node *temp = start;
    while (temp->next->next != NULL)
        temp = temp->next;
    free(temp->next);
    temp->next = NULL;
}

void deleteANode()
{
    if (start == NULL)
    {
        printf("\nList is empty");
        return;
    }
    int search;
    printf("Enter a value you want to delete : ");
    scanf("%d", &search);
    node *temp = start;
    while (temp->data != search)
    {
        if (temp->next == NULL)
        {
            printf("\nValue not found");
            return;
        }
        temp = temp->next;
    }
    if (temp == start)
        deleteAtFront();
    else if (temp->next == NULL)
        deleteAtBack();
    else
    {
        node *prev = start;
        while (prev->next != temp)
            prev = prev->next;
        prev->next = temp->next;
        free(temp);
    }
}

void display()
{
    if (start == NULL)
    {
        printf("\nList is empty");
        return;
    }
    node *newnode = start;
    while (newnode != NULL)
    {
        printf("%d --> ", newnode->data);
        newnode = newnode->next;
    }
}
                   
               

Circular Single Linked List

  • It is just a single linked list in which the link field of the last node points back to the address of the first node.
  • A circular linked list has no beginning and no end. It is necessary to establish a special pointer called start  pointer always pointing to the first node of the list.
  • Circular linked lists are frequently used instead of ordinary linked list because many operations are much easier to implement.
  • In circular linked list no null pointer are used, hence all pointers contain valid address.
                            
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
    int data;
    struct node *next;
} node;
node *start = NULL;

void insertAtFront();
void insertAtBack();
void insertAfterNode();
void deleteAtFront();
void deleteAtBack();
void deleteNode();
void display();

int main()
{
    int choice;
    while (1)
    {
        printf("\n------- MENU Circular single linked list ---------");
        printf("\n1. Insert at front");
        printf("\n2. Insert at back");
        printf("\n3. Insert after a node");
        printf("\n4. Delete at front");
        printf("\n5. Delete at back");
        printf("\n6. Delete a node");
        printf("\n7. Display");
        printf("\n8. Exit");
        printf("\nEnter you choice : ");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            insertAtFront();
            break;
        case 2:
            insertAtBack();
            break;
        case 3:
            insertAfterNode();
            break;
        case 4:
            deleteAtFront();
            break;
        case 5:
            deleteAtBack();
            break;
        case 6:
            deleteNode();
            break;
        case 7:
            display();
            break;
        case 8:
            exit(0);
        default:
            printf("\nEnter a correct choice");
        }
    }
    return 0;
}
void insertAtFront()
{
    node *newNode = (node *)malloc(sizeof(node));
    printf("Enter a value : ");
    scanf("%d", &newNode->data);
    if (start == NULL)
    {
        start = newNode;
        newNode->next = start;
    }
    else
    {
        newNode->next = start;
        start = newNode;
    }
}

void insertAtBack()
{
    node *newNode = (node *)malloc(sizeof(node));
    node *last = start;
    printf("Enter a value : ");
    scanf("%d", &newNode->data);
    newNode->next = NULL;
    if (start == NULL)
    {
        start = newNode;
        newNode->next = start;
    }
    else
    {
        while (last->next != start)
            last = last->next;
        last->next = newNode;
        newNode->next = start;
    }
}

void insertAfterNode()
{
    if (start == NULL)
    {
        printf("\nlist is empty, cannot insert after a node\n");
        return;
    }
    int node_val;
    printf("\nEnter a node value after which you want to insert : ");
    scanf("%d", &node_val);
    node *temp = start;
    while (temp->data != node_val)
    {
        if (temp->next == NULL)
        {
            printf("\nValue not found");
            return;
        }
        temp = temp->next;
    }
    node *newNode = (node *)malloc(sizeof(node));
    newNode->next = NULL;
    printf("\nEnter the value : ");
    scanf("%d", &newNode->data);
    newNode->next = temp->next;
    temp->next = newNode;
}

void deleteAtFront()
{
    if (start == NULL)
    {
        printf("\nNo node exist");
        return;
    }
    if (start->next == start) // there is only one element
    {
        free(start);
        start = NULL;
        return;
    }
    node *last = start, *temp = start;
    while (last->next != start)
        last = last->next;
    start = start->next;
    last->next = start;
    free(temp);
}

void deleteAtBack()
{
    if (start == NULL)
    {
        printf("\nNo node exist");
        return;
    }
    if (start->next == start) // only one element left
    {
        free(start);
        start = NULL;
        return;
    }
    node *temp = start;
    while (temp->next->next != start)
    {
        temp = temp->next;
    }
    free(temp->next);
    temp->next = start;
}

void deleteNode()
{
    if (start == NULL)
    {
        printf("\nNo node exist");
        return;
    }
    int search;
    printf("Enter a value you want to delete : ");
    scanf("%d", &search);
    node *temp = start;
    while (temp->data != search)
    {
        temp = temp->next;
        if (temp->next == NULL)
        {
            printf("\nValue not found");
            return;
        }
    }
    if (temp == start)
        deleteAtFront();
    else if (temp->next == start)
        deleteAtBack();
    else
    {
        node *prev = start;
        while (prev->next != temp)
        {
            prev = prev->next;
        }
        prev->next = temp->next;
    }
}

void display()
{
    if (start == NULL)
    {
        printf("\nEmpty list");
        return;
    }
    node *newNode = start;
    while (newNode->next != start)
    {
        printf("%d --> ", newNode->data);
        newNode = newNode->next;
    }
    printf("%d --> ", newNode->data);
}
                            
                        

Doubly Linked List:

                    
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
    struct node *prev;
    int data;
    struct node *next;
} node;
node *start = NULL;
void insert_front(int val)
{
    node *newNode = (node *)malloc(sizeof(node));
    newNode->data = val;
    newNode->prev = NULL;
    newNode->next = NULL;
    if (start == NULL)
    {
        start = newNode;
    }
    else
    {
        newNode->next = start;
        start->prev = newNode;
        start = newNode;
    }
}
void insert_last(int val)
{
    node *newNode = (node *)malloc(sizeof(node));
    newNode->next = NULL;
    newNode->prev = NULL;
    newNode->data = val;

    if (start == NULL)
    {
        start = newNode;
    }
    else
    {
        node *ptr = start;
        while (ptr->next != NULL)
        {
            ptr = ptr->next;
        }
        newNode->prev = ptr;
        ptr->next = newNode;
    }
}
void insertAfterANode()
{
    if (start == NULL)
    {
        printf("\nList is empty, cannot insert a node");
        return;
    }
    int ele;
    printf("Enter the element after which you insert new element : ");
    scanf("%d", &ele);
    node *ptr = start;
    while (ptr->data != ele)
    {
        if (ptr->next == NULL)
        {
            printf("\n Element not found, cannot insert element");
            return;
        }
        ptr = ptr->next;
    }
    node *newNode = (node *)malloc(sizeof(node));
    newNode->next = NULL;
    newNode->prev = NULL;
    printf("Enter the node value : ");
    scanf("%d", &newNode->data);
    if (ptr == start)
    {
        newNode->prev = start;
        start->next = newNode;
    }
    else if (ptr->next == NULL)
    {
        ptr->next = newNode;
        newNode->prev = ptr;
    }
    else
    {
        newNode->next = ptr->next;
        newNode->prev = ptr;
        ptr->next->prev = newNode;
        ptr->next = newNode;
    }
}
void delete_front()
{
    if (start == NULL)
    {
        printf("\t\tUnderflow");
        return;
    }
    if (start->next == NULL)
        start = NULL;
    else
    {
        node *ptr = start;
        start = start->next;
        ptr->next = NULL;
        start->prev = NULL;
        free(ptr);
    }
}
void delete_last()
{

    if (start == NULL)
    {
        printf("\t\tUnderflow");
        return;
    }
    node *ptr = start;
    while (ptr->next != NULL)
    {
        ptr = ptr->next;
    }
    if (ptr->prev == NULL)
        start = NULL;
    else
    {
        ptr->prev->next = NULL;
        ptr->prev = NULL;
        free(ptr);
    }
}
void deleteNode()
{
    if (start == NULL)
    {
        printf("\t\tList is empty");
        return;
    }
    int ele;
    printf("Enter the element you want to delete : ");
    scanf("%d", &ele);
    node *ptr = start;
    while (ptr->data != ele)
    {
        if (ptr->next == NULL)
        {
            printf("\nElement not found");
            return;
        }
        ptr = ptr->next;
    }
    if (ptr == start)
    {
        delete_front();
    }
    else if (ptr->next == NULL)
    {
        delete_last();
    }
    else
    {
        ptr->next->prev = ptr->prev;
        ptr->prev->next = ptr->next;
        free(ptr);
    }
}
void display()
{

    if (start == NULL)
    {

        printf("\t\tUnderflow");
    }
    else
    {
        node *ptr = start;
        while (ptr != NULL)
        {
            printf("\t%d<=>", ptr->data);
            ptr = ptr->next;
        }
    }
}
int main()
{
    int ch, val, ele;
    while (1)
    {
        printf("\n1.insert in began\n2.insert in end\n3.insert after node");
        printf("\n4.Delete in front\n5.Delete in last\n6.Delete a node");
        printf("\n7.Display\n8.Exit\n");
        printf("Enter your choice : ");
        scanf("%d", &ch);

        switch (ch)
        {
        case 1:
        {
            printf("Enter the  data value : ");
            scanf("%d", &val);
            insert_front(val);
            break;
        }
        case 2:
        {
            printf("Enter the data value : ");
            scanf("%d", &val);
            insert_last(val);
            break;
        }

        case 3:
        {
            insertAfterANode();
            break;
        }

        case 4:
            delete_front();
            break;

        case 5:
            delete_last();
            break;

        case 6:
            deleteNode();
            break;

        case 7:
            display();
            break;

        case 8:
            exit(0);

        default:
            printf("Wrong input mate !!");
            break;
        }
    }
    return 0;
}
                    
                

Circular Double Linked List

  • A circular double linked list has both sucessor and predecessor pointer in circular manner. The object behind considering circular double linked list is to simplify the insertion and deletion operations performed on double linked list.
  • In circular double linked list the right link of the right most node points back to the start node and left link of the first node points to the last node.

Garbage collection and Compaction

Garbage collection

  • Garbage collection is the process of automatically reclaiming memory that is no longer in use by the program.
  • In the context of linked lists, garbage collection involves identifying and deallocating unused nodes.
  • Node becomes unused when they are no longer reachable from the list's head node.
  • Garbage collection ensures efficient memory utilization and prevents memory leaks.
  • Mark and Sweep algorithm: It is a common technique used for garbage collection in linked lists.
    • This algorithm consists of two phases: marking and sweeping.
    • In the marking phase, the algorithm traverses the linked list from the head node and marks all reachable nodes.
    • Marking can be done by setting a flag or modifying a field in each node.
    • In the sweeping phase, the algorithm traverses the linked list again and deallocates all unmarked nodes.
    • The memory occupied by unmarked nodes is returned to the system for reuse.

Using free to deallocate the unnecessary nodes

  • After marking the reachable nodes during the mark phase of the mark and sweep algorithm, you need to deallocate the memory for the unmarked nodes.Traverse the linked list and for each unmarked node, use free() to release the memory occupied by that node.
  • For example ↓
                           
// Assuming a linked list node structure like:
struct Node {
    int data;
    struct Node* next;
};

// During garbage collection, deallocate unmarked nodes
struct Node* current = head;
while (current != NULL) {
    struct Node* nextNode = current->next;
    if (!current->marked) {
        free(current);  // Deallocate memory for unmarked node
    }
    current = nextNode;
}

                           
                       

Compaction

  • Compaction is an optimization technique that aims to reduce memory fragmentation in a linked list.
  • Memory fragmentation occurs when free memory blocks are scattered throughout the memory space.
  • Compaction rearranges the nodes in memory to eliminate fragmentation and create a contiguous block of free memory.
  • The compaction process involves iterating over the linked list, moving the nodes closer together, and updating the pointers accordingly.
  • After compaction, the linked list occupies a compact memory space, which improves memory utilization and reduces memory allocation overhead.

Using free() in Compaction

  • During the compaction process, you rearrange the nodes to eliminate memory fragmentation and create a contiguous block of free memory.
  • As you move nodes, you will have "gaps" or unused memory spaces left behind.
  • To reclaim this unused memory, you can use free() to deallocate those gaps.
  • For example ↓
                        
// Assuming a linked list node structure like:
struct Node {
    int data;
    struct Node* next;
};

// Perform compaction and deallocate gaps
struct Node* current = head;
struct Node* prev = NULL;
while (current != NULL) {
    // Move the node to its new position
    // ...

    // Deallocate the gap between prev and current
    if (prev != NULL && prev->next != current) {
        struct Node* gap = prev->next;
        prev->next = current;
        free(gap);  // Deallocate memory for the gap
    }

    prev = current;
    current = current->next;
}