Circular Linked List in Data Structure: Types & its Implementation

Published: 13 Dec 2024 | Reading Time: 6 min read

Introduction

A linked list is a linear data structure containing nodes where each node has a value and reference such as links to the next node of the list. A circular linked list is a loop of the data structure where the last node in the list connects to the first node. This article delves into the concept, implementation, and applications of circular linked lists.

What is a Circular Linked List?

A Circular Linked List (CLL) is a data structure in which a group of nodes are connected to form a circle, where the last node points back to the first node. This means that there is no terminating null pointer at the end of the list.

Types of Circular Linked Lists

The two main types of circular linked lists are:

1. Circular Singly Linked List

In a Circular Singly Linked List, each node points to the next node, and the last node points back to the first node. It allows one-way traversal, i.e., you can traverse the list from the head node to the last node and back to the head.

2. Circular Doubly Linked List

A Circular Doubly Linked List is more advanced as each node contains two pointers where one pointing to the next node and another pointing to the previous node. The last node points to the head, and the head points to the last node, forming a circle.

Basic Operations on Circular Linked List

Here are the basic operations performed on the circular linked list:

1. Insertion

2. Deletion

3. Traversal

Traverse all nodes starting from a given node and looping back to the start.

4. Searching

Find a specific node in the circular linked list.

Implementation of Circular Linked List in Data Structure

Here is the implementation of a circular linked list in data structures in C, C++, and Java:

C Code Implementation

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

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

struct Node* head = NULL;

// Function to insert at the beginning
void insertAtBeginning(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    if (head == NULL) {
        newNode->next = newNode;  // Point to itself if it's the only node
        head = newNode;
    } else {
        struct Node* temp = head;
        while (temp->next != head)
            temp = temp->next;
        temp->next = newNode;
        newNode->next = head;
        head = newNode;
    }
}

// Function to insert at the end
void insertAtEnd(int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    if (head == NULL) {
        newNode->next = newNode;
        head = newNode;
    } else {
        struct Node* temp = head;
        while (temp->next != head)
            temp = temp->next;
        temp->next = newNode;
        newNode->next = head;
    }
}

// Function to display the circular linked list
void displayList() {
    if (head == NULL) {
        printf("List is empty.\n");
        return;
    }
    struct Node* temp = head;
    do {
        printf("%d -> ", temp->data);
        temp = temp->next;
    } while (temp != head);
    printf("(head)\n");
}

int main() {
    insertAtBeginning(10);
    insertAtBeginning(20);
    insertAtEnd(30);
    insertAtEnd(40);
    displayList();  // Output: 20 -> 10 -> 30 -> 40 -> (head)
    return 0;
}

C++ Code Implementation

#include <iostream>
using namespace std;

class CircularLinkedList {
public:
    struct Node {
        int data;
        Node* next;
    };
    Node* head;

    CircularLinkedList() {
        head = nullptr;
    }
    
    // Function to insert at the beginning
    void insertAtBeginning(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* temp = head;
            while (temp->next != head) temp = temp->next;
            temp->next = newNode;
            newNode->next = head;
            head = newNode;
        }
    }

    // Function to insert at the end
    void insertAtEnd(int data) {
        Node* newNode = new Node();
        newNode->data = data;
        if (!head) {
            newNode->next = newNode;
            head = newNode;
        } else {
            Node* temp = head;
            while (temp->next != head) temp = temp->next;
            temp->next = newNode;
            newNode->next = head;
        }
    }

    // Function to display the circular linked list
    void displayList() {
        if (!head) {
            cout << "List is empty.\n";
            return;
        }
        Node* temp = head;
        do {
            cout << temp->data << " -> ";
            temp = temp->next;
        } while (temp != head);
        cout << "(head)" << endl;
    }
};

int main() {
    CircularLinkedList cll;
    cll.insertAtBeginning(10);
    cll.insertAtBeginning(20);
    cll.insertAtEnd(30);
    cll.insertAtEnd(40);
    cll.displayList();  // Output: 20 -> 10 -> 30 -> 40 -> (head)
    return 0;
}

Java Code Implementation

class CircularLinkedList {
    static class Node {
        int data;
        Node next;

        Node(int data) {
            this.data = data;
            this.next = null;
        }
    }

    private Node head = null;

    // Insert at the beginning
    public void insertAtBeginning(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node temp = head;
            while (temp.next != head)
                temp = temp.next;
            temp.next = newNode;
            newNode.next = head;
            head = newNode;
        }
    }

    // Insert at the end
    public void insertAtEnd(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            newNode.next = newNode;
            head = newNode;
        } else {
            Node temp = head;
            while (temp.next != head)
                temp = temp.next;
            temp.next = newNode;
            newNode.next = head;
        }
    }

    // Display the list
    public void displayList() {
        if (head == null) {
            System.out.println("List is empty.");
            return;
        }
        Node temp = head;
        do {
            System.out.print(temp.data + " -> ");
            temp = temp.next;
        } while (temp != head);
        System.out.println("(head)");
    }

    public static void main(String[] args) {
        CircularLinkedList cll = new CircularLinkedList();
        cll.insertAtBeginning(10);
        cll.insertAtBeginning(20);
        cll.insertAtEnd(30);
        cll.insertAtEnd(40);
        cll.displayList();  // Output: 20 -> 10 -> 30 -> 40 -> (head)
    }
}

Advantages and Disadvantages of Circular Linked List

Here are the advantages and disadvantages of a circular linked list in data structures:

Advantages

Disadvantages

What are the Applications of Circular Linked List?

Here are the applications that use circular linked lists in real life:

1. Round Robin Scheduling

Circular Linked Lists are used in scheduling algorithms like round-robin scheduling, where each process is allocated a fixed time slot in a cyclic manner.

2. Memory Management

In memory management systems, Circular Linked Lists are used to manage memory blocks in a circular fashion, which allows efficient memory reuse.

3. Game Development

In games, Circular Linked Lists are used to manage players cyclically. For example, in a multiplayer game, the turn of players can be managed using a Circular Linked List.

4. Data Buffering

Circular Linked Lists are often used in buffering data in networking applications where the buffer is reused circularly.

Conclusion

In conclusion, a circular linked list is a flexible data structure with practical applications in real life. It offers insertion and deletion operations, efficient memory utilization, and suitable applications in multi-programming operating systems and games with multiple players. However, they also require more complex algorithms and can be error-prone if not implemented correctly.

Frequently Asked Questions

1. How do you insert a new node at the beginning of a Circular Linked List?

To insert a new node at the beginning, create a new node and make it point to the current head (which is the tail->next). Once this is done, update the current tail's next node to point to the new one. As a final step, update the head reference to point to the new node.

2. Can Circular Linked Lists be implemented using singly linked lists or doubly linked lists?

Yes, Circular Linked Lists can be implemented using either singly linked lists or doubly linked lists. The main difference is that the last node in a circular linked list points back to the first node, whereas in a regular linked list, the last node points to NULL.

3. How do you handle errors or edge cases in Circular Linked Lists?

When implementing Circular Linked Lists, it's essential to handle errors and edge cases, such as inserting a new node at an invalid position, deleting a non-existent node, or traversing an empty list. Proper error handling and boundary checking can help prevent bugs and ensure the reliability of your implementation.

Related Articles


Source: NxtWave (CCBP.in)

Contact: [email protected] | +919390111761 (WhatsApp only)