A circular doubly linked list is a python data structure wherein data elements are stored as nodes. Circular doubly linked lists are similar to doubly linked lists. The only difference is that their first and last nodes are interconnected as well.
The head node holds a reference to the tail node and vice versa. Hence, in a circular doubly linked list we can perform circular traversal by jumping from the first node to the last node or from the last node to the first node.
Creation of a Circular Doubly Linked List
To create a circular doubly linked list, we initialize the node and linked list class. Next, we set up our list by creating its first element and assigning the “head” and “tail” references to it.
Algorithm to create a Circular Doubly Linked List
- Step 1: Create a node class with the three required data variables.
- Step 2: Create the Circular Doubly Linked List class and declare the head and tail nodes.
- Step 3: Create a new node and assign it a value.
- step 4: Set the “next” reference of the newly created node to none.
- Step 5: Set the “prev” reference of the newly created node to none.
- Step 6: Set both the head and tail references to the new node.
- Step 7: Terminate.
Method to create a Circular Doubly Linked List
#Creating the Node class
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
#Create a circular doubly linked list class to initialize head and tail references
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
#Function to create Circular Doubly Linked List
def createCDLL(self, value):
new_node = Node(value)
new_node.next = None
new_node.prev = None
self.head = new_node
self.tail = new_node
print("The circular doubly linked list has been created.")
#Initialize the linked list with a new node
circulardoublyLL = CDoublyLinkedList()
circulardoublyLL.createCDLL(5)
print([node.value for node in circulardoublyLL])
#Output
The circular doubly linked list has been created.
[5]
The iterator function
Since the custom-created linked list is not iterable, we have to add an “__iter__” function so as to traverse through the list.
#Iterator Function
def __iter__(self):
node = self.head
while node:
yield node
node = node.next
if node == self.tail.next:
break
Time and Space Complexity
The time complexity for initializing a circular doubly linked list is O(1). The space complexity is O(1) as no additional memory is required to initialize the linked list.
Insertion in Circular Doubly Linked List
A node can be inserted in a circular doubly linked list in any one of the following three ways.
- At the beginning of the linked list
- In between the linked list
- At the end of the linked list
Insertion Algorithm
Algorithm to insert a node at the beginning
- Step 1: Create a node and assign a value to it.
- Step 2: Assign the “prev” reference of head as the new node.
- Step 3: Assign the “next” reference of the node as head.
- Step 4: Set the created node as the new head.
- Step 5: Assign the “next” reference of tail to head and the “prev” reference of head to tail.
- Step 6: Terminate.
Method to insert a node at the beginning
#Insertion at the beginning in a Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
#Function to add node in the beginning
def atBeg(self, value):
new_node = Node(value)
self.head.prev = new_node
new_node.next = self.head
self.head = new_node
self.tail.next = self.head
self.head.prev = self.tail
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
cdll.atBeg(0)
print([node.value for node in cdll])
#Output
[0, 1, 3, 5, 7, 9]
Algorithm to insert a node in between the linked list
- Step 1: Create a node and assign a value to it.
- Step 2: If the previous node doesn’t exist, return an error message and move to step 5.
- Step 3: Set the “next” reference of the previous node to the new node and set the “prev” reference of the new node to the previous node.
- Step 4: Set the “next” reference of the new node to the next node and set the “prev” reference of the next node to the new node.
- Step 5: Terminate.
Method to insert a node in between the linked list
#Insertion in between a Circular Doubly Linked List
#Function to add node in the middle
def inMid(self,prev_node, value):
if prev_node is None:
print("Mentioned node doesn't exist")
return
next_node = prev_node.next
new_node = Node(value)
prev_node.next = new_node
new_node.prev = prev_node
new_node.next = next_node
next_node.prev = new_node
#Initially, we have a linked list (1,3,5,7,9) called "cdll" and "prev" node points to the value 3.
cdll.inMid(prev, 11)
print([node.value for node in cdll])
#Output
[1, 3, 11, 5, 7, 9]
Algorithm to insert a node at the end of the linked list
- Step 1: Create a node and assign a value to it.
- Step 2: If the list is empty, assign new node to head and tail. Move to step 7.
- Step 3: Search for the last node. Once found, set its “next” reference pointing to the new node.
- Step 4: Set the “prev” reference of the new node to the last node.
- Step 5: Assign the new node as tail.
- Step 6: Assign the “next” reference of tail to head and the “prev” reference of head to tail.
- Step 7: Terminate.
Method to insert a node at the end of the linked list
#Insertion at the end in a Circular Doubly Linked List
#Function to add node in the end
def atEnd(self, value):
new_node = Node(value)
if self.head is None:
self.head = new_node
self.tail = new_node
return
last_node = self.head
while(last_node.next != self.head):
last_node = last_node.next
last_node.next = new_node
new_node.prev = last_node
self.tail = new_node
self.tail.next = self.head
self.head.prev = self.tail
#Initially, we have a linked list (1,3,5,7,9) called "dll".
dll.atEnd(0)
print([node.value for node in dll])
#Output
[1, 3, 5, 7, 9, 0]
Time and Space Complexity
Instead of iterating over the linked list and reaching the required position, we can directly jump to any point in python. Therefore, the time complexity of insertion in a circular doubly linked list is O(1).
But, for insertion at the end, the time complexity is O(N) as we need to traverse to the last element. The space complexity is O(1) because it takes a constant space to add a new node.
Traversal in Circular Doubly Linked List
Forward Traversal
A circular doubly linked list can be traversed in the forward direction by iterating from the first element to the last. We get the value of the next data element by simply iterating with the help of the reference address.
Forward Traversing Method
#Forward Traversal through Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def printForwardList(self):
if self.head == None:
print("The linked list does not exist.")
else:
temp_node = self.head
while temp_node:
print(temp_node.value)
if temp_node == self.tail:
break
temp_node = temp_node.next
#Initially, we have a linked list (1, 3, 5, 7, 9) called "cdll".
cdll.printForwardList()
#Output
1
3
5
7
9
Reverse Traversal
A circular doubly linked list can be traversed in the reverse direction by iterating from the last element to the first. We get the value of the previous data element by simply iterating with the help of the reference address.
Reverse Traversing Method
#Reverse Traversal through Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def printReverseList(self):
if self.head == None:
print("The linked list does not exist.")
else:
temp_node = self.tail
while temp_node:
print(temp_node.value)
if temp_node == self.head:
break
temp_node = temp_node.prev
#Initially, we have a linked list (1, 3, 5, 7, 9) called "cdll".
cdll.printReverseList()
#Output
9
7
5
3
1
Time and Space Complexity
We need to loop over the linked list to traverse and print every element. The time complexity for traversal is O(N) where ‘N’ is the size of the given linked list. The space complexity is O(1) as no additional memory is required to traverse through a circular doubly linked list.
Searching in a Circular Doubly Linked List
To find a node in a given circular doubly linked list, we can use the technique of traversal. The only difference, in this case, is that as soon as we find the searched node, we will terminate the loop.
The worst-case scenario for search is when we have the required element at the end of the linked list, in such a case we have to iterate through the entire linked list to find the required element.
Searching Algorithm
- Step 1: If the linked list is empty, return the message and move to step 5.
- Step 2: Iterate over the linked list using the reference address for each node.
- Step 3: Search every node for the given value.
- Step 4: If the element is found, break the loop. If not, return the message “Element not found”.
- Step 5: Terminate.
Searching Method
#Searching in a Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def searchList(self, value):
position = 0
found = 0
if self.head is None:
print("The linked list does not exist")
else:
temp_node = self.head
while temp_node:
position = position + 1
if temp_node.value == value:
print("The required value was found at position: " + str(position))
found = 1
break
if temp_node == self.tail:
print("The required value does not exist in the list")
break
temp_node = temp_node.next
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
print(cdll.searchList(7))
#Output
The required value was found at position: 4
Time and Space Complexity
The time complexity for searching a given element in the linked list is O(N) as we have to loop over all the nodes and check for the required one. The space complexity is O(1) as no additional memory is required to traverse through a circular doubly linked list and perform a search.
Deletion of node from Circular Doubly Linked List
To delete an existing node from a circular doubly linked list, we must know the value that the node holds. For deletion, we first locate the node previous to the given node. Then we point the “next” reference of this node to the next node and the “prev” reference to the previous node.
A node can be deleted from a circular doubly linked list in any one of the following three ways.
- Deleting the first node
- Deleting any given node
- Deleting the last node
Deletion Algorithm
Algorithm to delete a node from the beginning
- Step 1: If the linked list is empty, return a null statement and go to step 7.
- Step 2: If there’s only one element, delete that node and set head and tail to none. Go to step 7.
- Step 3: Set a “next_node” pointing to the element next to the head node.
- Step 4: Set the “prev” reference of “nex_node” to none.
- Step 5: Assign “next_node” as the new head.
- Step 6: Assign “head” to the “next” reference of the tail and “tail” to the “prev” reference of head.
- Step 7: Terminate.
Method to delete a node from the beginning
#Deletion at the beginning of a Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
#Function to delete node from the beginning
def delBeg(self):
if(self.head == None):
return
elif (self.head.next == self.tail.next):
self.head = self.tail = None
return
elif (self.head is not None):
next_node = self.head.next
next_node.prev = None
self.head = next_node
self.tail.next = self.head
self.head.prev = self.tail
return
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
cdll.delBeg()
print([node.value for node in cdll])
#Output
[3, 5, 7, 9]
Algorithm to delete a node from between the linked list
- Step 1: If the linked list is empty, return a null statement and go to step 7.
- Step 2: Create a “temp_node” and set it to the head node. Iterate over the list till the element to be deleted is found.
- Step 3: Set “prev_node” as the element behind the node to be deleted.
- Step 4: Set “next_node” as the element after the node to be deleted.
- Step 5: Assign the “next” reference of “prev_node” to the “next_node”.
- Step 6: Assign the “prev” reference of “next_node” to the “prev_node”.
- Step 7: Terminate.
Method to delete a node from between the linked list
#Function to delete a node from between the linked list
def delMid(self, del_value):
if(self.head == None):
return
temp_node = self.head
found = False
while (temp_node) :
if(temp_node.value == del_value):
found = True
break
temp_node = temp_node.next
if (found == True):
prev_node = temp_node.prev
next_node = temp_node.next
prev_node.next = next_node
next_node.prev = prev_node
return
else:
print("Element not found.")
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
cdll.delMid(3)
print([node.value for node in cdll])
#Output
[1, 5, 7, 9]
Algorithm to delete a node from the end
- Step 1: If the linked list is empty, return a null statement and go to step 7.
- Step 2: If there’s only one element, delete that node and set head and tail to none. Go to step 7.
- Step 3: Set a “temp_node” pointing at head. Iterate the linked list till that node points to the second last node of the list.
- Step 4: Assign tail as the temp node. Set temp node to the next node, i.e., last in the list.
- Step 5: Delete the temp_node.
- Step 6: Assign “head” to the “next” reference of the tail and “tail” to the “prev” reference of head.
- Step 7: Terminate.
Method to delete a node from the end
#Function to delete node from the end
def delEnd(self):
if(self.head == None):
return
elif (self.head.next == self.tail.next):
self.head = self.tail = None
return
else:
temp_node = self.head
while (temp_node.next is not self.tail):
temp_node = temp_node.next
self.tail = temp_node
temp_node.next = None
self.tail.next = self.head
self.head.prev = self.tail
return
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
cdll.delEnd()
print([node.value for node in cdll])
#Output
[1, 3, 5, 7]
Time and Space Complexity
The time complexity for deletion in a circular doubly linked list is O(N) as we have to loop over all the nodes and search for the required one. The space complexity is O(1) as no additional memory is required to delete an element from a circular doubly linked list.
Deletion of entire Circular Doubly Linked List
The deletion of an entire circular doubly linked list is quite a simple process. We need to set the previous references of all nodes in the list to none. Then, we have to set the two reference nodes “head” and “tail” to none.
Algorithm to delete an entire circular doubly linked list
- Step 1: If the linked list is empty, return an error message and go to step 6.
- Step 2: Set the “next” reference of the tail to none.
- Step 3: Iterate over the linked list and set all the previous references to none.
- Step 4: Delete the “head” node by setting it to none.
- Step 5: Delete the “tail” node by setting it to none.
- Step 6: Terminate.
Method to delete an entire circular doubly linked list
#Deletion of an entire Circular Doubly Linked List
class Node:
def __init__(self, value = None):
self.value = value
self.next = None
self.prev = None
class CDoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def delCDLL(self):
if self.head is None:
print("The circular doubly linked list does not exist.")
else:
self.tail.next = None
temp_node = self.head
while (temp_node):
temp_node.prev = None
temp_node = temp_node.next
self.head = None
self.tail.next = None
self.tail = None
print("The circular doubly linked list has been deleted.")
#Initially, we have a linked list (1,3,5,7,9) called "cdll".
cdll.delDLL()
#Output
The circular doubly linked list has been deleted.
Time and Space Complexity
The time complexity for deletion of an entire circular doubly linked list is O(N) because we need to iterate over the entire list to set all previous references to none. The space complexity is O(1) since there is no additional space required when deleting the references.