Doubly Linked Circular List

A Doubly Linked Circular List is an advanced data structure that combines the benefits of both doubly linked lists and circular lists. This structure allows for efficient traversal in both directions and ensures that the last node in the list links back to the first one, creating a continuous loop. Understanding this structure is essential for managing complex data tasks, such as in-memory databases, circular queues, and task scheduling systems. This article provides a detailed overview of what a doubly linked circular list is, its operations, and its advantages.

Doubly Linked Circular List Example

Doubly Linked Circular List is similar to a doubly linked list but only one key difference is, that the next pointer of the last node points to the first node, and the previous pointer of the first node points to the last node, creating a circular structure. This ensures that traversing the list is continuous and seamless.

The node structure is also similar for both Doubly Linked Circular List is similar to doubly linked lists where each node contains three key components:

  1. Data: Stores the information or value.
  2. Next Pointer: Points to the next node in the list.
  3. Previous Pointer: Points to the previous node in the list.

Doubly Linked Circular List - Node Structure

Key Operations in a Doubly Linked Circular List

Insertion, deletion and traversal are the major key operations which are used in doubly linked circular list

1. Insertion:

  • At the Beginning: A new node is added before the first node. The previous pointer of the first node is updated to point to the new node, and the next pointer of the last node is updated to point to the new node.
  • At the End: A new node is added after the last node. The next pointer of the new node points to the first node, while the previous pointer of the first node is updated to point to the new node.
  • In the Middle: A new node can be inserted at any position in the list by adjusting the pointers of the neighboring nodes.

2. Deletion:

  • At the Beginning: The first node is removed. The previous pointer of the second node is updated to point to the last node, and the next pointer of the last node is updated to point to the second node.
  • At the End: The last node is removed. The next pointer of the second-to-last node is updated to point to the first node, while the previous pointer of the first node is updated to point to the second-to-last node.
  • In the Middle: Any node can be deleted by adjusting the next and previous pointers of its neighboring nodes.

3. Traversal:

  • Forward Traversal:  Starting from any node, we can traverse in the forward direction using the next pointers.
  • Backward Traversal:  Similarly, we can traverse the list in the backward direction using the previous pointers.

Example: Doubly Linked Circular List

It is circular because:

  • The last node’s Next pointer (550 → 350) points back to the first node.
  • The first node’s Prev pointer (350 → 550) points back to the last node.

Doubly Linked Circular List Example

Node-by-Node Explanation

1. First Node

  • Memory Address: 350
  • Prev (Address): 550 (points to the last node, completing the circular link).
  • Data: 50
  • Next (Address): 450 (points to the second node).

2. Second Node

  • Memory Address: 450
  • Prev (Address): 350 (points to the first node).
  • Data: 60
  • Next (Address): 550 (points to the last node).

3. Last Node

  • Memory Address: 550
  • Prev (Address): 450 (points to the second node).
  • Data: 70
  • Next (Address): 350 (points back to the first node, completing the circular structure).

The following table also explains it in a very descriptive manner

Addressing in Doubly Linked Circular List

Advantages of Doubly Linked Circular List

A Doubly Linked Circular List combines the features of doubly linked and circular linked lists, offering unique advantages:

  • Bidirectional Traversal: A doubly linked circular list allows traversal in both directions (forward and backward). This is especially useful when you need to access data from both ends of the list efficiently.
  • Efficient Insertion and Deletion: Insertion and deletion operations are more efficient, particularly when dealing with circular operations like buffer management, where nodes are frequently added or removed.
  • No NULL Pointers: In a circular list, no node points to NULL. The list is always circular, meaning there is no end, and the list can be traversed continuously. This feature is useful in scenarios like circular queues, where the elements must wrap around.
  • Memory Optimization: In situations requiring cyclic data management (like event loops or round-robin scheduling), a doubly linked circular list allows for seamless data cycling, reducing the need to reallocate memory or adjust pointers frequently.

Applications of Doubly Linked Circular Lists

A Doubly Linked Circular List is a versatile data structure used in various applications due to its dynamic and circular nature. Here are some practical use cases:

  • Task Scheduling Systems: A doubly linked circular list is ideal for scheduling tasks in a round-robin manner, where tasks are continuously cycled through without a specific start or end.
  • Circular Buffers: For applications involving streaming data or network buffers, where data is continually written and read, a circular list ensures that the buffer is always in use without requiring constant reset.
  • Memory Management: Doubly linked circular lists are used in memory management systems, where blocks of memory are continuously recycled, making it easy to track available and used blocks.
  • Navigational Systems: In applications like web browsers or media players, a circular doubly linked list can efficiently manage navigation between previous and next items, such as web pages or songs in a playlist.

Implementing a Doubly Linked Circular List in Code

Here’s a basic implementation of a doubly linked circular list in C:


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

// Define a structure for a node in the doubly linked circular list
typedef struct Node {
int data;
struct Node* next;
struct Node* prev;
} Node;

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

// Function to insert a node at the end of the list
Node* insertEnd(Node* head, int data) {
Node* newNode = createNode(data);

if (head == NULL) { // Empty list
return newNode;
}

Node* tail = head->prev;
tail->next = newNode;
newNode->prev = tail;
newNode->next = head;
head->prev = newNode;
return head;
}

// Function to display the list
void displayList(Node* head) {
if (head == NULL) {
printf("List is empty!\n");
return;
}

Node* current = head;
printf("List elements: ");
do {
printf("%d ", current->data);
current = current->next;
} while (current != head);
printf("\n");
}

int main() {
Node* head = NULL;

// Insert nodes
head = insertEnd(head, 50);
head = insertEnd(head, 60);
head = insertEnd(head, 70);

// Display list
displayList(head);

return 0;
}

Output:
List elements: 50 60 70

Summary Table

Feature Singly Linked List Doubly Linked List Doubly Linked Circular List
Forward Traversal
Backward Traversal
Circular (Infinite Traversal)
Insertion/Deletion Efficiency Medium High High
Dynamic Size
Starting Point Flexibility
Conclusion: A Doubly Linked Circular List offers significant advantages in terms of memory management, data traversal, and insertion or deletion efficiency. Its ability to connect the last node to the first creates a continuous loop that is beneficial for many applications, including scheduling, buffering, and memory management. Understanding and implementing this structure can enhance performance in scenarios where circular data management is required.