![]() |
VOOZH | about |
A doubly linked list is a type of linked list in which each node contains 3 parts, a data part and two addresses, one points to the previous node and one for the next node. It differs from the singly linked list as it has an extra pointer called previous that points to the previous node, allowing the traversal in both forward and backward directions.
In this article, we will learn about the doubly linked list implementation in C. We will also look at the working of the doubly linked list and the basic operations that can be performed using the doubly linked list in C.
A doubly linked list is represented in C as the pointer to the head (i.e. first node) in the list. Each node in a doubly linked list contains three components:
To implement a doubly linked list in C first, we need to define a node that has three parts: data, a pointer to the next node, and a pointer to the previous node, and then create a new node.
We can create a node using the structure which allows us to combine different data types into single type.
To define a structure of a node in doubly linked list use the below format:
struct Node {
int data;
struct Node* next;
struct Node* prev;
}
We can then dynamically create the node using malloc() and assign the values to the next, prev and data fields. It is generally preferred to create a function that creates a node, assign the data field and return the pointer to that node.
We can perform the following basic operations in a doubly-linked list:
Inserting a new node in a doubly linked list can be done in a similar way like inserting a new node in a singly linked list but we have to maintain the link of previous node also. We have three scenarios while inserting a node in a doubly linked list:
👁 Insertion_beginning_Doubly-Linked-List
To insert a new node at the beginning of the doubly linked list follow the below approach:
Approach:
- Create a newNode with data field assigned the given value.
- If the list is empty:
- Set newNode->next to NULL.
- Set newNode->prev to NULL.
- Update the head pointer to point to newNode.
- If the list is not empty:
- Set newNode->next to head.
- Set newNode->prev to NULL.
- Set head->prev to newNode.
- Update the head pointer to point to newNode.
Time Complexity: O(1), as insertion is done at front so we are not traversing through the list.
Space Complexity: O(1)
To insert a new node at the end of the doubly linked list, follow the below approach:
Approach:
- Create a newNode with data field assigned the given value.
- If the list is empty:
- Set newNode->next to NULL.
- Set newNode->prev to NULL.
- Update the head pointer to point to newNode.
- If the list is not empty:
- Traverse the list to find the last node (where last->next == NULL).
- Set last->next to newNode.
- Set newNode->prev to last.
- Set newNode->next to NULL.
Time Complexity: O(n), as insertion is done at the end, so we need to traverse through the list.
Space Complexty: O(1)
For inserting a node at a specific position in a doubly linked list follow the below approach:
Approach:
- Create a newNode.
- Find the size of the list to ensure the position is within valid bounds.
- If the position is 0 (or 1 depending on your indexing):
- Use the insertion at the beginning approach.
- If the position is equal to the size of the list:
- Use the insertion at the end approach.
- If the position is valid and not at the boundaries:
- Traverse the list to find the node immediately before the desired insertion point (prevNode).
- Set newNode->next to prevNode->next.
- Set newNode->prev to prevNode.
- If prevNode->next is not NULL, set prevNode->next->prev to newNode.
- Set prevNode->next to newNode.
Time Complexity: O(n), as insertion is done in between, so we need to traverse through the list until we reach the desired position.
Space Complexity: O(1)
Just like insertion, we have three scenarios while deleting a node in a doubly linked list:
To delete a node at the beginning of the doubly linked list, follow the below approach:
Approach:
- Check if the List is Empty: If true, there's nothing to delete.
- Check if the List Contains Only One Node:
- Set head to NULL.
- Free the memory of the node.
- If the List Contains More Than One Node:
- Update head to head->next.
- Set the prev of the new head to NULL.
- Free the memory of the old head.
Time Complexity: O(1), as deletion is done at front so we are not traversing through the list.
To delete a node at the end of the doubly linked list, follow the below approach:
Approach:
- Check if the List is Empty: If true, there's nothing to delete.
- If the List is Not Empty:
- Traverse to the last node using a loop.
- Check if the last node is the only node (head->next == NULL):
- Update head to NULL.
- If more than one node:
- Set the next of the second last node (last->prev) to NULL.
- Free the memory of the last node.
Time Complexity: O(n), as deletion is done at the end, so we need to traverse through the list. If a tail pointer is maintained, this operation can be optimized to O(1) by directly accessing the last node.
For deleting a node at a specific position in a doubly linked list, follow the below approach:
Approach:
- Check Position Validity:
- If position is 0 (or 1 depending on indexing), use deletion at the beginning.
- If position is the size of the list, use deletion at the end.
- Otherwise, proceed with the middle deletion.
- Traverse to the Specified Position:
- Use a loop to reach the node (delNode) at the desired position.
- If delNode is the first node, adjust head.
- If not, adjust delNode->prev->next and delNode->next->prev if delNode->next is not NULL.
- Free the Memory:
- Release the node to be deleted.
Time Complexity: O(n), as deletion is done in between, as we may need to traverse up to n elements to find the correct position.
Traversal in a doubly linked list means visiting each node of the doubly linked list to perform some kind of operation like displaying the data stored in that node. Unlike singly linked list we can traverse in doubly linked list in both the directions.
For traversing in a forward direction in a doubly linked list, follow the below approach:
Approach:
- Create a temporary pointer ptr and copy the head pointer into it.
- Traverse through the list using a while loop.
- Keep moving the value of temp pointer variable ptr to ptr->next until the last node whose next part contains null is found.
- During each iteration of the loop, perform the desired operation.
Time Complexity: O(n), as we need to traverse through the whole list containing n number of nodes.
For traversing in a reverse direction in a doubly linked list, follow the below approach:
- Create a temporary pointer ptr and copy the tail pointer into it.
- Traverse through the list using a while loop.
- Keep moving the value of temp pointer variable ptr to ptr->prev until the first node whose prev part contains null is found.
- During each iteration of the loop, perform the desired operation .
Time Complexity: O(n), as here also we need to traverse through the whole list containing n number of nodes.
The below program demonstrates all the major operations of a doubly linked list: insertion (at the beginning, at the end, and at a specific position), deletion (at the beginning, at the end, and at a specific position), and traversal (forward and reverse).
After Insertions: Forward List: 5 15 10 20 Reverse List: 20 10 15 5 After Deletions: Forward List: 15