For working professionals
For fresh graduates
More
Data Structure Tutorial: Every…
1. Data Structure
2. Types of Linked Lists
3. Array vs Linked Lists in Data Structure
4. Stack vs. Queue Explained
5. Singly Linked List
6. Circular doubly linked list
Now Reading
7. Circular Linked List
8. Stack Implementation Using Array
9. Circular Queue in Data Structure
10. Dequeue in Data Structures
11. Bubble Sort Algorithm
12. Insertion Sort Algorithm
13. Shell Sort Algorithm
14. Radix Sort
15. Counting Sort Algorithm
16. Trees in Data Structure
17. Tree Traversal in Data Structure
18. Inorder Traversal
19. Optimal Binary Search Trees
20. AVL Tree
21. Red-Black Tree
22. B+ Tree in Data Structure
23. Expression Tree
24. Adjacency Matrix
25. Spanning Tree in Data Structure
26. Kruskal Algorithm
27. Prim's Algorithm in Data Structure
28. Bellman Ford Algorithm
29. Ford-Fulkerson Algorithm
30. Trie Data Structure
31. Floyd Warshall Algorithm
32. Rabin Karp Algorithm
33. What Is Dynamic Programming?
34. Longest Common Subsequence
35. Fractional Knapsack Problem
36. Greedy Algorithm
37. Longest Increasing Subsequence
38. Matrix Chain Multiplication
39. Subset Sum Problem
40. Backtracking Algorithm
41. Huffman Coding Algorithm
42. Tower of Hanoi
43. Stack vs Heap
44. Asymptotic Analysis
45. Binomial Distribution
46. Coin Change Problem
47. Fibonacci Heap
48. Skip List in Data Structure
49. Sparse Matrix
50. Splay Tree
51. Queue in Data Structure
52. Stack in Data Structure
53. Time and Space Complexity
54. Linked List in Data Structure
55. Stack And Queue: Roles & Functions
56. Doubly Linked List
57. Strongly Connected Components
58. Bucket Sort Algorithm
I clearly remember an intense coding competition in which I ran into an issue that at first looked impossible. The assignment? Effectively modify a dataset for real-time analysis. I had a breakthrough and realized that the secret to solving the problem might lie in a circular, doubly linked list. The structure's elegance amazed me as I methodically threaded nodes together, getting into the implementation. It was a revelation: bidirectional traversal and smooth data manipulation. Circular doubly linked lists were my first choice for situations needing effective navigation and dynamic data management after that.
Circular doubly linked lists are advanced data structures characterized by nodes that hold references to both their previous and next nodes. Unlike singly linked lists, circular doubly linked lists do not contain NULL pointers, creating a circular arrangement where the last node points back to the first, and the first node points to the last.
The structure of a circular doubly linked list consists of three main components per node: the data, a pointer to the previous node, and a pointer to the next node. This design allows for efficient traversal in both forward and backward directions, as nodes can be easily accessed from any point in the list.
The circular doubly linked list implementation involves carefully threading nodes together.
class Node:
def __init__(self, data):
self.data = data
self.prev = None
self.next = None
The Node class represents individual nodes of the circular doubly linked list, where every node contains data and pointers to the previous and next nodes.
class CircularDoublyLinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = new_node
new_node.prev = new_node
else:
last_node = self.head.prev
last_node.next = new_node
new_node.prev = last_node
new_node.next = self.head
self.head.prev = new_node
The Circular Doubly Linked List class manages the circular doubly linked list. The append technique adds a new node to the end of the list. If the list is null, then the new node becomes the head and points to itself.
Insertion operations can be performed at various positions in the list:
def insert_at_beginning(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = new_node
new_node.prev = new_node
else:
last_node = self.head.prev
last_node.next = new_node
new_node.prev = last_node
new_node.next = self.head
self.head.prev = new_node
self.head = new_node
Time complexity: O(1)
Explanation: Inserting at the beginning involves creating a new node and adjusting a few pointers (the new node's next and prev, and the current head and tail nodes' next and prev). This is a constant time operation.
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = new_node
new_node.prev = new_node
else:
last_node = self.head.prev
last_node.next = new_node
new_node.prev = last_node
new_node.next = self.head
self.head.prev = new_node
Time complexity: O(1)
Explanation: Inserting at the end, like at the beginning, involves creating a new node and updating the pointers of the tail and head nodes. This operation is also constant time.
def insert_at_position(self, data, position):
if position == 0:
self.insert_at_beginning(data)
else:
new_node = Node(data)
current = self.head
for _ in range(position - 1):
current = current.next
new_node.next = current.next
new_node.prev = current
current.next.prev = new_node
current.next = new_node
Time complexity: O(n)
Explanation: Inserting at a specific position requires traversing the list to that position, which in the worst case involves n steps (where n is the number of nodes). Once at the position, the insertion is O(1).
Deletion operations can also be performed at various positions in the list:
def delete_at_beginning(self):
if not self.head:
return
if self.head.next == self.head:
self.head = None
else:
last_node = self.head.prev
self.head = self.head.next
last_node.next = self.head
self.head.prev = last_node
Time complexity: O(1)
Explanation: Deleting the first node involves updating the head pointer and the previous head node's pointers. If the list becomes empty, additional handling is required to set the head and tail to null.
def delete_at_end(self):
if not self.head:
return
if self.head.next == self.head:
self.head = None
else:
last_node = self.head.prev
last_node.prev.next = self.head
self.head.prev = last_node.prev
Time complexity: O(1)
Explanation: Deleting the last node involves updating the tail pointer and the previous tail node's pointers. Similar to deletion at the beginning, if the list becomes empty, the head and tail need to be set to null.
def delete_at_position(self, position):
if not self.head:
return
if position == 0:
self.delete_at_beginning()
else:
current = self.head
for _ in range(position):
current = current.next
current.prev.next = current.next
current.next.prev = current.prev
Time complexity: O(n)
Explanation: Deleting a node at a specific position requires traversing the list to that position (O(n) time) and then adjusting the pointers of the neighboring nodes (O(1) time).
Efficient memory management in circular doubly linked lists involves proper node allocation/deallocation and handling circular references to avoid memory leaks.
Circular doubly linked lists inherently have circular references, which can be problematic for garbage collection in some languages. Care must be taken to break these references when nodes are deleted, or the list is destroyed.
When modifying the list (inserting or deleting nodes), minimize the number of pointer updates required. Keeping track of the head and tail pointers ensures operations at the ends of the list remain efficient.
Circular doubly linked lists find diverse applications across various domains:
Circular doubly linked lists find applications in various data structures due to their unique properties, including:
Circular doubly linked lists are also employed in various real-world applications, including:
The circular doubly linked list offers advantages that make it a versatile and powerful data structure.
Here's a simple example code demonstrating the implementation of a circular doubly linked list:
class Node:
def __init__(self, data):
self.data = data
self.prev = None
self.next = None
class CircularDoublyLinkedList:
def __init__(self):
self.head = None
def append(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = new_node
new_node.prev = new_node
else:
last_node = self.head.prev
last_node.next = new_node
new_node.prev = last_node
new_node.next = self.head
self.head.prev = new_node
def display(self):
if not self.head:
print("List is empty")
return
current = self.head
while True:
print(current.data, end=" ")
current = current.next
if current == self.head:
break
print("->", end=" ")
# Example usage
if __name__ == "__main__":
cdl = CircularDoublyLinkedList()
cdl.append(1)
cdl.append(2)
cdl.append(3)
cdl.append(4)
print("Circular Doubly Linked List:")
cdl.display()
This code defines a Node class to represent individual nodes of the circular doubly linked list and a CircularDoublyLinkedList class to manage the list. The append technique adds a new node at the end of the list, and the display technique prints the elements of the list.
The circular doubly linked list is an excellent example of how sophisticated data structures can be both elegant and effective. Its special circular structure and bidirectional traversal capabilities enable dynamic data management and smooth navigation. This structure has invaluable uses in many disciplines, from computer science to media players, despite its increased complexity and memory overhead.
1. What is an example of a doubly linked list?
A list where each node contains a reference to both its previous and next nodes, allowing bidirectional traversal.
2. Is the circular linked list single or double?
A circular linked list is neither single nor double; it's a distinct type where the last node points back to the first, forming a circular structure.
3. How is a circular linked list different?
Unlike linear linked lists, a circular linked list doesn't have a distinct end; instead, its last node points back to the first, creating a continuous loop.
4. What is the circular doubly linked list?
The circular doubly linked list is a variation of the doubly linked list where the last node points to the first, and the first node points to the last, forming a circular structure.
5. What is the difference between DLL and DCLL?
The main difference between DLL (Doubly Linked List) and DCLL (Circular Doubly Linked List) is that DCLL's last node points to the first, creating a circular structure.
6. What is a circular linked list in detail?
It is a linked list where the last node directs back to the first, forming a circular structure. It's useful for applications requiring continuous data processing or looping navigation.
Author
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918045604032
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.