Doubly Linked List in C (original) (raw)

Last Updated : 23 Jul, 2025

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.

**Doubly Linked List Representation 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:

  1. **Data: data is the actual information stored in the node.
  2. **Next: nextis apointer that links to the next node in the list.
  3. **Prev: previous is a pointer that links to the previous node in the list.

DLL1

Doubly Linked List

**Implementation of Doubly Linked List in C

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.

**Define a Node in Doubly Linked List

NodeDoublyLinkedList-(1)

Node-Doubly Linked List

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.

**Basic Operations on C Doubly Linked List

We can perform the following basic operations in a doubly-linked list:

1. Insertion in Doubly Linked List in C

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:

**a. Insertion at the Beginning of the 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:

**Time Complexity: O(1), as insertion is done at front so we are not traversing through the list.
**Space Complexity: O(1)

b. **Insertion at the End of the Doubly Linked List

Insertion_end_Doubly-Linked-List

Insertion at the end in doubly linked list

To insert a new node at the end of the doubly linked list, follow the below approach:

**Approach:

**Time Complexity: O(n), as insertion is done at the end, so we need to traverse through the list.
**Space Complexty: O(1)

c. Insertion in the Middle of the Doubly Linked List

Insertion_middle_Doubly-Linked-List

Insertion in the middle of doubly linked list

For inserting a node at a specific position in a doubly linked list follow the below approach:

**Approach:

**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)

2. Deletion in a Doubly Linked List in C

Just like insertion, we have three scenarios while deleting a node in a doubly linked list:

a. **Deletion at the Beginning of the Doubly Linked List

Deletion_beginning_DLL

To delete a node at the beginning of the doubly linked list, follow the below approach:

**Approach:

**Time Complexity: O(1), as deletion is done at front so we are not traversing through the list.

b. **Deletion at the End of the Doubly Linked List

Deletion_end_DLL

To delete a node at the end of the doubly linked list, follow the below approach:

**Approach:

**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.

c. **Deletion at a Specific Position in Doubly Linked List

Deletion_specificNode_DLL

For deleting a node at a specific position in a doubly linked list, follow the below approach:

**Approach:

**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.

3. Traversal in a Doubly Linked List in C

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.

**a. Forward Traversal in Doubly Linked List

For traversing in a forward direction in a doubly linked list, follow the below approach:

**Approach:

**Time Complexity: O(n), as we need to traverse through the whole list containing n number of nodes.

**b. Reverse Traversal in Doubly Linked List

For traversing in a reverse direction in a doubly linked list, follow the below approach:

**Time Complexity: O(n), as here also we need to traverse through the whole list containing n number of nodes.

C Program to Implement Doubly Linked List

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).

C `

// C Program to Implement Doubly Linked List #include <stdio.h> #include <stdlib.h>

// defining a node typedef struct Node { int data; struct Node* next; struct Node* prev; } Node;

// Function to create a new node with given value as data Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; newNode->prev = NULL; return newNode; }

// Function to insert a node at the beginning void insertAtBeginning(Node** head, int data) { // creating new node Node* newNode = createNode(data);

// check if DLL is empty
if (*head == NULL) {
    *head = newNode;
    return;
}
newNode->next = *head;
(*head)->prev = newNode;
*head = newNode;

}

// Function to insert a node at the end void insertAtEnd(Node** head, int data) { // creating new node Node* newNode = createNode(data);

// check if DLL is empty
if (*head == NULL) {
    *head = newNode;
    return;
}

Node* temp = *head;
while (temp->next != NULL) {
    temp = temp->next;
}
temp->next = newNode;
newNode->prev = temp;

}

// Function to insert a node at a specified position void insertAtPosition(Node** head, int data, int position) { if (position < 1) { printf("Position should be >= 1.\n"); return; }

// if we are inserting at head
if (position == 1) {
    insertAtBeginning(head, data);
    return;
}
Node* newNode = createNode(data);
Node* temp = *head;
for (int i = 1; temp != NULL && i < position - 1; i++) {
    temp = temp->next;
}
if (temp == NULL) {
    printf(
        "Position greater than the number of nodes.\n");
    return;
}
newNode->next = temp->next;
newNode->prev = temp;
if (temp->next != NULL) {
    temp->next->prev = newNode;
}
temp->next = newNode;

}

// Function to delete a node from the beginning void deleteAtBeginning(Node** head) { // checking if the DLL is empty if (head == NULL) { printf("The list is already empty.\n"); return; } Node temp = *head; *head = (*head)->next; if (*head != NULL) { (*head)->prev = NULL; } free(temp); }

// Function to delete a node from the end void deleteAtEnd(Node** head) { // checking if DLL is empty if (*head == NULL) { printf("The list is already empty.\n"); return; }

Node* temp = *head;
if (temp->next == NULL) {
    *head = NULL;
    free(temp);
    return;
}
while (temp->next != NULL) {
    temp = temp->next;
}
temp->prev->next = NULL;
free(temp);

}

// Function to delete a node from a specified position void deleteAtPosition(Node** head, int position) { if (head == NULL) { printf("The list is already empty.\n"); return; } Node temp = *head; if (position == 1) { deleteAtBeginning(head); return; } for (int i = 1; temp != NULL && i < position; i++) { temp = temp->next; } if (temp == NULL) { printf("Position is greater than the number of " "nodes.\n"); return; } if (temp->next != NULL) { temp->next->prev = temp->prev; } if (temp->prev != NULL) { temp->prev->next = temp->next; } free(temp); }

// Function to print the list in forward direction void printListForward(Node* head) { Node* temp = head; printf("Forward List: "); while (temp != NULL) { printf("%d ", temp->data); temp = temp->next; } printf("\n"); }

// Function to print the list in reverse direction void printListReverse(Node* head) { Node* temp = head; if (temp == NULL) { printf("The list is empty.\n"); return; } // Move to the end of the list while (temp->next != NULL) { temp = temp->next; } // Traverse backwards printf("Reverse List: "); while (temp != NULL) { printf("%d ", temp->data); temp = temp->prev; } printf("\n"); }

int main() { Node* head = NULL;

// Demonstrating various operations
insertAtEnd(&head, 10);
insertAtEnd(&head, 20);
insertAtBeginning(&head, 5);
insertAtPosition(&head, 15, 2); // List: 5 15 10 20

printf("After Insertions:\n");
printListForward(head);
printListReverse(head);

deleteAtBeginning(&head); // List: 15 10 20
deleteAtEnd(&head); // List: 15 10
deleteAtPosition(&head, 2); // List: 15

printf("After Deletions:\n");
printListForward(head);

return 0;

}

`

Output

After Insertions: Forward List: 5 15 10 20 Reverse List: 20 10 15 5 After Deletions: Forward List: 15

**Advantages of Doubly Linked List

**Disadvantages of Doubly Linked List