Linked Lists: A Beginner-Friendly Guide with Code Examples

If you’re delving into data structures, chances are you’ve encountered the term linked list. They’re a powerful alternative to arrays, especially when you need flexibility in managing data. This blog will introduce you to linked lists, explain some key terms, and go over a few basic operations with example code. Let’s get started!

What is a Linked List?

A linked list is a sequence of nodes where each node holds:

  1. Data: The actual value you want to store.

  2. Pointer (or Link): A reference to the next node in the sequence.

Unlike arrays, linked lists don’t require contiguous memory allocation. This makes them ideal for situations where data is frequently added or removed.

Types of Linked Lists

  1. Singly Linked List: Each node points to the next node, forming a unidirectional chain.

  2. Doubly Linked List: Each node has pointers to both the next and previous nodes, allowing traversal in both directions.

  3. Circular Linked List: The last node links back to the first, creating a circular structure.


Key Terms

  • Node: The building block of a linked list, containing data and a pointer.

  • Head: The first node in a linked list.

  • Tail: The last node in a singly linked list (or the node before the head in a circular list).

  • Pointer: A reference in each node that points to the next node (or previous, in doubly linked lists).


Basic Linked List Operations with Code Examples

Let’s look at some common operations on a linked list, with brief explanations of each.

Creating a Node

In most programming languages, we define a Node class to represent each node in the list. Here’s a basic structure for a node in a singly linked list:

pythonCopy codeclass Node:
    def __init__(self, data):
        self.data = data  # Store data
        self.next = None  # Initialize next as null

Each node stores a data element and a next pointer, which initially points to None.

Q1. A program to insert data into a linked list.

  • Create a new node.

  • Point the next of this new node to the current head.

  • Update the head to the new node.

// Linked list: Inserting a node at beginning
#include <stdio.h>
#include <stdlib.h>
struct Node {
    int data;
    struct Node* next;
};
struct Node* head = NULL;  // Initialize head to NULL
void Insert(int x) {
    struct Node* temp = (struct Node*)malloc(sizeof(struct Node)); // Allocate memory for the new node
    if (temp == NULL) { // Check if memory allocation was successful
        printf("Memory allocation failed\n");
        return;
    }
    temp->data = x;
    temp->next = head;
    head = temp;
}
void Print() {
    struct Node* temp = head;
    printf("List: ");
    while (temp != NULL) {
        printf("%d ", temp->data);
        temp = temp->next;
    }
    printf("\n");
}
int main() {
    int n, x;
    printf("How many numbers? ");
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        printf("Enter the number: ");
        scanf("%d", &x);
        Insert(x);
        Print();
    }
    return 0;
}

Q2 Program to get 2 linked lists and add them to an array.

    #include<stdio.h>
    #include<stdlib.h>
    struct node{
        int data;
        struct node* next;
    };
    struct node *head=NULL,*newnode,*temp=NULL;
    int main(){
        int arr[6];


        printf("Enter the numbers of 1st list:\n");
        for(int i=0;i<3;i++){
            struct node* newnode=(struct node*)malloc(sizeof(struct node));
            if(newnode==NULL){
            printf("Memory full\n");
            return 1;
        }
            scanf("%d",&newnode->data);
            arr[i]=newnode->data;
            newnode->next=0;
            if(head==NULL){
                head=temp=newnode;
            }
            else{
                temp->next=newnode;
                temp=newnode;
            }
        }
        printf("Enter the numbers of 2nd list:\n");
        for(int i=0;i<3;i++){
            struct node* newnode2=(struct node*)malloc(sizeof(struct node));
        if(newnode2==NULL){
            printf("Memory full\n");
            return 1;
        }
            scanf("%d",&newnode2->data);
            arr[i+3]=newnode2->data;
            newnode2->next=0;
            if(head==NULL){
                head=temp=newnode2;
            }
            else{
                temp->next=newnode2;
                temp=newnode2;
            }
        }
        int swap;
        for (int i=0;i<6-1;i++){
            for (int j=0;j<6-i-1;j++){
                if(arr[j]>arr[j+1]){
                swap=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=swap;
                }
            }
        }
        for(int i=0;i<6;i++){
            printf("%d,",arr[i]);
        }
        // temp=head;
        // printf("list:");
        // while(temp!=NULL){
        //  printf("%d,",temp->data);
        //  temp=temp->next;
        // }
        printf("\n");
    }

Q3 Same code but save the data in the array in a list

    #include<stdio.h>
    #include<stdlib.h>
    struct node{
        int data;
        struct node* next;
    };
    struct node *head=NULL,*newnode,*temp=NULL;
    int main(){
        int arr[6];


        printf("Enter the numbers of 1st list:\n");
        for(int i=0;i<3;i++){
            struct node* newnode=(struct node*)malloc(sizeof(struct node));
            if(newnode==NULL){
            printf("Memory full\n");
            return 1;
        }
            scanf("%d",&newnode->data);
            arr[i]=newnode->data;
            newnode->next=0;
            if(head==NULL){
                head=temp=newnode;
            }
            else{
                temp->next=newnode;
                temp=newnode;
            }
        }
        printf("Enter the numbers of 2nd list:\n");
        for(int i=0;i<3;i++){
            struct node* newnode2=(struct node*)malloc(sizeof(struct node));
        if(newnode2==NULL){
            printf("Memory full\n");
            return 1;
        }
            scanf("%d",&newnode2->data);
            arr[i+3]=newnode2->data;
            newnode2->next=0;
            if(head==NULL){
                head=temp=newnode2;
            }
            else{
                temp->next=newnode2;
                temp=newnode2;
            }
        }
        int swap;
        for (int i=0;i<6-1;i++){
            for (int j=0;j<6-i-1;j++){
                if(arr[j]>arr[j+1]){
                swap=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=swap;
                }
            }
        }
        for(int i=0;i<6;i++){
            printf("%d,",arr[i]);
        }
        temp=head;
        printf("list:");
        for(int i=0;i<6&& temp!=NULL;i++){
            temp->data=arr[i];
            temp=temp->next;
        }
        temp=head;
        printf("list:");
        while(temp!=NULL){
            printf("%d,",temp->data);
            temp=temp->next;
        }
        printf("\n");
        return 0;
    }

Inserting a Node at the End

To add a node at the end:

  1. Traverse to the last node.

  2. Update the last node’s next pointer to the new node.

pythonCopy codedef insert_at_end(head, data):
    new_node = Node(data)
    if not head:
        return new_node  # If list is empty, new node is the head
    temp = head
    while temp.next:
        temp = temp.next
    temp.next = new_node
    return head

A functions which add data in the begenning, end and middle.

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};
struct node *head,*begenningnode,*endnode,*temp,*given;
void begenning(){//Insert data in the begenning
    struct node* begenningnode=(struct node*)malloc(sizeof(struct node));
    printf("Enter data :");
    scanf("%d",&begenningnode->data);
    begenningnode->next=head;
}
void ending(){//Insert node in the end
    struct node* endnode=(struct node*)malloc(sizeof(struct node));
    printf("Enter data :");
    scanf("%d",&endnode->data);
    endnode->next=0;
    temp=head;
    while(temp->next!=0){
        temp=temp->next;
    }
    temp->next=endnode;
}
int pas,i=1;
void given(count){

    printf("Enter data :");
    scanf("%d",&pas);
    if(pas>count){
        print("Invalid input");
    }
    else
    {
        temp=head;
        while(i<pas){
            temp=temp->next;
            i++;
            if(i>count){
                return 1;
            }
        }
        struct node* given=(struct node*)malloc(sizeof(struct node));
        printf("Enter data:");
        scanf("%d",&given->data);
        given->next=temp->next;
        temp->next=given;
    }
}
int main(){
    // Just functions So no execution
}

Deleting a Node

To delete a node:

  1. Traverse the list to find the node to delete.

  2. Adjust the next pointer of the previous node to skip over the node to delete.

pythonCopy codedef delete_node(head, key):
    temp = head
    if temp and temp.data == key:
        return temp.next  # Head needs to be removed
    while temp and temp.next and temp.next.data != key:
        temp = temp.next
    if temp and temp.next:
        temp.next = temp.next.next  # Bypass the node to delete
    return head

Q4 A program to take a linked list and ask the user if he wants to add a node in the begenning middle or end.

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};
struct node *head=NULL,*temp=NULL,*newnode,*beg,*end,*mid,*prev;
int count=0;
void printt(){
    temp=head;
    printf("List:");
    while(temp!=NULL){
        printf("%d ",temp->data);
        temp=temp->next;
    }
}
void bege(){
    struct node* beg=(struct node*)malloc(sizeof(struct node));
    printf("Enter value:");
    scanf("%d",&beg->data);
    beg->next=head;
    head=beg;
    printt();
}
void endd(){
    struct node* end=(struct node*)malloc(sizeof(struct node));
    printf("Enter value:");
    scanf("%d",&end->data);
    end->next=0;
    temp=head;
    while(temp->next!=0){
        temp=temp->next;
    }
    temp->next=end;
    printt();
}
void midd(){
    int p,i;
    printf("Enter postion start from 0:");
    scanf("%d",&p);
    if(p>count){
        printf("Invalid");
        return;
        }
        else{
        temp=head;
        while(i<p){
            temp=temp->next;
            if(i>count){
                return;
            }}
        }
        struct node* mid=(struct node*)malloc(sizeof(struct node));
        printf("Enter value:");
        scanf("%d",&mid->data);
        mid->next=temp->next;
        temp->next=mid;
        printt();
}
int main(){

    int x=0;
    printf("Enter number of value:");
    scanf("%d",&x);
    for(int i=0;i<x;i++){
        struct node* newnode=(struct node*)malloc(sizeof(struct node));
        if(newnode==NULL){
        printf("Memory full\n");
        return 1;
        }
        printf("Enter value %d:",count);
        scanf("%d",&newnode->data);
        newnode->next=0;
        if(head==NULL){
        head=temp=newnode;
    }
    else{
        temp->next=newnode;
        temp=newnode;
    }
    count++;
    }
    printt();
    int pos=0;
    printf("Where do you want to enter a node\n 1=begenning,2=end,3=given postion:\n");
    scanf("%d",&pos);
    if (pos==1){
        bege();
    }
    else if(pos==2){
        endd();
    }
    else if(pos==3){
        midd();
    }
    else if(pos==0){
        return 0;
    }
}

Q5 A program to take a linked list and ask the user if he wants to add a node in the begenning middle or end and to ask if they wanna delete any data.

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};
struct node *head=NULL,*temp=NULL,*newnode,*beg,*end,*mid,*prev,*dell;
int count=0;
void printt(){
    temp=head;
    printf("List:");
    while(temp!=NULL){
        printf("%d ",temp->data);
        temp=temp->next;
    }
}
void delt(){
    int d=0;
    int i;
    printf("Enter the postion you wanna delete from 0:\n");
    scanf("%d",&d);
    temp=head;
    while(i<d-1){
        temp=temp->next;
        i++;
    }
    dell=temp->next;
    temp->next=dell->next;
    printt();
    free(temp);
}
void bege(){
    struct node* beg=(struct node*)malloc(sizeof(struct node));
    printf("Enter value:");
    scanf("%d",&beg->data);
    beg->next=head;
    head=beg;
    printt();
}
void endd(){
    struct node* end=(struct node*)malloc(sizeof(struct node));
    printf("Enter value:");
    scanf("%d",&end->data);
    end->next=0;
    temp=head;
    while(temp->next!=0){
        temp=temp->next;
    }
    temp->next=end;
    printt();
}
void midd(){
    int p,i;
    printf("Enter postion start from 0:");
    scanf("%d",&p);
    if(p>count){
        printf("Invalid");
        return;
        }
        else{
        temp=head;
        while(i<p){
            temp=temp->next;
            if(i>count){
                return;
            }}
        }
        struct node* mid=(struct node*)malloc(sizeof(struct node));
        printf("Enter value:");
        scanf("%d",&mid->data);
        mid->next=temp->next;
        temp->next=mid;
        printt();
}
int main(){

    int x=0;
    printf("Enter number of value:");
    scanf("%d",&x);
    for(int i=0;i<x;i++){
        struct node* newnode=(struct node*)malloc(sizeof(struct node));
        if(newnode==NULL){
        printf("Memory full\n");
        return 1;
        }
        printf("Enter value %d:",count);
        scanf("%d",&newnode->data);
        newnode->next=0;
        if(head==NULL){
        head=temp=newnode;
    }
    else{
        temp->next=newnode;
        temp=newnode;
    }
    count++;
    }
    printt();
    int pos=0;
    printf("Where do you want to enter a node\n 1=begenning,2=end,3=given 4=delete from a given point.postion:\n");
    scanf("%d",&pos);
    if (pos==1){
        bege();
    }
    else if(pos==2){
        endd();
    }
    else if(pos==3){
        midd();
    }
    else if(pos==4){
        delt();
    }
    else if(pos==0){
        return 0;
    }
}

Making a doubly linked list

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*prev,*next;
};
struct node *head=NULL,*temp=NULL,*newnode,*beg,*end,*mid,*dell,*y,*wemp;
int count;
void printt(){
    temp=head;
    printf("List:");
    while(temp!=NULL){
        printf("[%d|%d|%d] ",temp->prev,temp->data,temp->next);
        temp=temp->next;
    }
}
int main(){

    int x=0;
    printf("Enter number of value:");
    scanf("%d",&x);
    for(int i=0;i<x;i++){
        struct node* newnode=(struct node*)malloc(sizeof(struct node));
        if(newnode==NULL){
        printf("Memory full\n");
        return 1;
        }
        printf("Enter value %d:",count);
        scanf("%d",&newnode->data);
        newnode->next=0;
        if(head==NULL){
        head=temp=newnode;
        wemp=head;
    }
    else{
        temp->next=newnode;
        temp->prev=wemp;
        wemp=temp;
        temp=newnode;

    }
    count++;
    }
    printt();

}

Why Linked Lists?

Linked lists might seem more complex than arrays, but they shine in situations where data is frequently inserted and removed. They’re used in real-world applications like:

  • Memory management in operating systems

  • Undo functionality in applications (like Ctrl + Z)

  • File systems for efficient file handling


Conclusion

Linked lists offer flexibility that arrays simply can’t match, especially when it comes to dynamic data. While they may require more memory and careful pointer management, their versatility makes them invaluable in many applications. By understanding the basics and practicing with code, you’ll see why linked lists are a go-to structure for developers worldwide.I’d like to express my gratitude to Jenny ma'am for creating YouTube videos on data structures. Her tutorials have been incredibly helpful in teaching core concepts to countless students.

Happy coding!