Doubly Linked List in C – A Comprehensive Tutorial

A Doubly Linked List is a type of linked list where each node points to both its previous and next nodes. This allows easy traversal in both directions, unlike singly linked lists that only move forward. Doubly linked lists are useful for operations like inserting or deleting nodes efficiently from any position.

In this tutorial, you’ll learn how to create and manage doubly linked lists in C, including key operations like insertion, deletion, and traversal, with clear explanations and example code.

Table of Contents:

What is a Doubly Linked List?

A doubly linked list is a kind of linked list in which each node has two pointers or references: one to the previous node in the sequence and one to the next node in the series. This enables the traversal of the list in both forward and backward directions.

In a doubly linked list, the first node is connected to a NULL reference in the previous pointer because there is no node before it. And the final node is connected to a NULL reference in the next pointer because there is no node after it. Each node in the list contains a data element as well as two pointers to the previous and next nodes in the sequence.

What is a Doubly Linked List?

Doubly linked lists are handy data structures for implementing lists, queues, and stacks, among other data structures. They have various advantages over singly-linked lists, including the ability to traverse the list in both ways, which makes them efficient for some algorithms. Nevertheless, because of the extra pointer in each node, they require more memory than singly-linked lists.

Here is a doubly linked list Structure syntax:

struct node.
<span style="font-weight: 400">struct node</span>
<span style="font-weight: 400">{</span>
<span style="font-weight: 400">    struct node *prev;</span>
<span style="font-weight: 400">    int data;</span>
<span style="font-weight: 400">    struct node *next;</span>
<span style="font-weight: 400">};</span>

Algorithm for Doubly Linked List in C

Here is the coding algorithm for the doubly linked list program in C:

<span style="font-weight: 400">struct node {</span>
<span style="font-weight: 400">    int data;</span>
<span style="font-weight: 400">    struct node* next;</span>
<span style="font-weight: 400">    struct node* prev;</span>
<span style="font-weight: 400">};</span>
 
<span style="font-weight: 400">struct node* head = NULL;</span>
<span style="font-weight: 400">struct node* tail = NULL;</span>

// create a new node with the given data and return a pointer to it

<span style="font-weight: 400">struct node* create_node(int data) {</span>
<span style="font-weight: 400">    struct node* new_node = (struct node*)malloc(sizeof(struct node));</span>
<span style="font-weight: 400">    new_node->data = data;</span>
<span style="font-weight: 400">    new_node->next = NULL;</span>
<span style="font-weight: 400">    new_node->prev = NULL;</span>
<span style="font-weight: 400">    return new_node;</span>
<span style="font-weight: 400">}</span>

// insert a node at the beginning of the list

<span style="font-weight: 400">void insert_at_head(int data) {</span>
<span style="font-weight: 400">    struct node* new_node = create_node(data);</span>
<span style="font-weight: 400">    if (head == NULL) {</span>
<span style="font-weight: 400">        head = new_node;</span>
<span style="font-weight: 400">        tail = new_node;</span>
<span style="font-weight: 400">    } else {</span>
<span style="font-weight: 400">        new_node->next = head;</span>
<span style="font-weight: 400">        head->prev = new_node;</span>
<span style="font-weight: 400">        head = new_node;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">}</span>

// insert a node at the end of the list

<span style="font-weight: 400">void insert_at_tail(int data) {</span>
<span style="font-weight: 400">    struct node* new_node = create_node(data);</span>
<span style="font-weight: 400">    if (tail == NULL) {</span>
<span style="font-weight: 400">        head = new_node;</span>
<span style="font-weight: 400">        tail = new_node;</span>
<span style="font-weight: 400">    } else {</span>
<span style="font-weight: 400">        new_node->prev = tail;</span>
<span style="font-weight: 400">        tail->next = new_node;</span>
<span style="font-weight: 400">        tail = new_node;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">}</span>

//delete the node at the beginning of the list

<span style="font-weight: 400">void delete_at_head() {</span>
<span style="font-weight: 400">    if (head == NULL) {</span>
<span style="font-weight: 400">        return;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    struct node* temp = head;</span>
<span style="font-weight: 400">    if (head == tail) {</span>
<span style="font-weight: 400">        head = NULL;</span>
<span style="font-weight: 400">        tail = NULL;</span>
<span style="font-weight: 400">    } else {</span>
<span style="font-weight: 400">        head = head->next;</span>
<span style="font-weight: 400">        head->prev = NULL;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    free(temp);</span>
<span style="font-weight: 400">}</span>

// delete the node at the end of the list

<span style="font-weight: 400">void delete_at_tail() {</span>
<span style="font-weight: 400">    if (tail == NULL) {</span>
<span style="font-weight: 400">        return;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    struct node* temp = tail;</span>
<span style="font-weight: 400">    if (head == tail) {</span>
<span style="font-weight: 400">        head = NULL;</span>
<span style="font-weight: 400">        tail = NULL;</span>
<span style="font-weight: 400">    } else {</span>
<span style="font-weight: 400">        tail = tail->prev;</span>
<span style="font-weight: 400">        tail->next = NULL;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    free(temp);</span>
<span style="font-weight: 400">}</span>

//Display the list in the forward direction

<span style="font-weight: 400">void display_forward() {</span>
<span style="font-weight: 400">    struct node* current = head;</span>
<span style="font-weight: 400">    while (current != NULL) {</span>
<span style="font-weight: 400">        printf("%d ", current->data);</span>
<span style="font-weight: 400">        current = current->next;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    printf("n");</span>
<span style="font-weight: 400">}</span>

//Display the list in the backward direction

<span style="font-weight: 400">void display_backward() {</span>
<span style="font-weight: 400">    struct node* current = tail;</span>
<span style="font-weight: 400">    while (current != NULL) {</span>
<span style="font-weight: 400">        printf("%d ", current->data);</span>
<span style="font-weight: 400">        current = current->prev;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    printf("n");</span>
<span style="font-weight: 400">}</span>

// main function to test the doubly linked list

<span style="font-weight: 400">int main() {</span>
<span style="font-weight: 400">    insert_at_head(1);</span>
<span style="font-weight: 400">    insert_at_head(2);</span>
<span style="font-weight: 400">    insert_at_tail(3);</span>
 
<span style="font-weight: 400">    display_forward();   // expected output: 2 1 3</span>
<span style="font-weight: 400">    display_backward();  // expected output: 3 1 2</span>
 
<span style="font-weight: 400">    delete_at_head();</span>
<span style="font-weight: 400">    delete_at_tail();</span>
 
<span style="font-weight: 400">    display_forward();   // expected output: 1</span>
<span style="font-weight: 400">    display_backward();  // expected output: 1</span>
 
<span style="font-weight: 400">    return 0;</span>
<span style="font-weight: 400">}</span>

Output:

________________________________________<br>
2 1 3<br>
3 1 2<br>
1<br>
1<br>
________________________________________<br>

Circular Doubly Linked List in C

A circular doubly linked list in C is a data structure that consists of a collection of nodes, where each node contains a data element and two pointers, one that points to the next node and another that points to the previous node. The circular doubly linked list is called “circular” because the last node in the list points back to the first node, creating a loop.

A circular doubly linked list is a data structure similar to a doubly linked list, except that the last node in the list refers back to the first node, forming a loop. This implies you can go through the list in both directions, from beginning to end and end to beginning.

The circular doubly linked list is made up of nodes, each of which has a data element and two pointers, one pointing to the next node and the other pointing to the previous node. The following figure depicts the construction of a circular doubly linked list:

Circular Doubly Linked List in C

Each node in the list, as shown in the figure, contains two pointers, one pointing to the previous node and one pointing to the next node. The circular loop is formed by the first node’s “prev” pointer pointing to the last node and the final node’s “next” pointer pointing to the first node.

Some of the operations that may be performed on a circular doubly linked list are as follows:

1. Insertion in Circular Doubly Linked List

To add a new node to a circular doubly linked list, construct a new node, set its data element, and then update the pointers of the nodes around it to include the new node. To insert a new node at the beginning of the list, for example, set the new node’s “prev” reference to the last node in the list and its “next” pointer to the current first node in the list. The last node’s “next” pointer would then be updated to refer to the new node, as would the first node’s “prev” pointer.

2. Deletion in Circular Doubly Linked List

To remove a node from a circular doubly linked list, adjust the pointers of the nodes around it to skip over the node you wish to remove. For example, if you wish to delete a node in the midst of the list, you would alter the previous node’s “next” reference to link to the next node, and the next node’s “prev” value to point to the prior node.

3. Traversal in Circular Doubly Linked List

To traverse a circular doubly linked list, start at any node and then follow the “next” pointers to travel ahead or the “prev” points to move backward. You can keep going down the list until you get back to the beginning.

4. Searching in Circular Doubly Linked List

To find a specific node in a circular doubly linked list, start at any node and compare its data element to the value you’re looking for. You’ve located the node if the data element matches. If the data element does not match, you can advance to the next node and retry the comparison by following the “next” or “prev” pointers.

Circular Doubly Linked List in C New

Algorithm for Circular Doubly Linked List in C

In C, here’s a method for creating a circular doubly linked list:

  1. Specify the structure of a list node.
  2. Declare a variable to maintain track of the list’s head node.
  3. Create a new node by implementing a function.
  4. Create a function to add a new node to the list.
  5. Create a function to remove a node from the list.
  6. Create a function that traverses the list.
  7. Create a function that searches the list for a node.

Here’s some C code that implements a circular doubly linked list using these algorithms:

// Define the node structure for the circular doubly linked list

<span style="font-weight: 400">struct Node {</span>
<span style="font-weight: 400">    int data;</span>
<span style="font-weight: 400">    struct Node* next;</span>
<span style="font-weight: 400">    struct Node* prev;</span>
<span style="font-weight: 400">};</span>

// Function to create a new node with the given data

<span style="font-weight: 400">struct Node* createNode(int data) {</span>
<span style="font-weight: 400">    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));</span>
<span style="font-weight: 400">    newNode->data = data;</span>
<span style="font-weight: 400">    newNode->next = NULL;</span>
<span style="font-weight: 400">    newNode->prev = NULL;</span>
<span style="font-weight: 400">    return newNode;</span>
<span style="font-weight: 400">}</span>

// Function to insert a new node into the circular doubly linked list

<span style="font-weight: 400">void insertNode(struct Node** head, struct Node* newNode) {</span>
<span style="font-weight: 400">    if (*head == NULL) {</span>
<span style="font-weight: 400">        *head = newNode;</span>
<span style="font-weight: 400">        newNode->next = newNode;</span>
<span style="font-weight: 400">        newNode->prev = newNode;</span>
<span style="font-weight: 400">        return;</span>
<span style="font-weight: 400">    }</span>
<span style="font-weight: 400">    struct Node* last = (*head)->prev;</span>
<span style="font-weight: 400">    newNode->next = *head;</span>
<span style="font-weight: 400">    (*head)->prev = newNode;</span>
<span style="font-weight: 400">    newNode->prev = last;</span>
<span style="font-weight: 400">    last->next = newNode;</span>
<span style="font-weight: 400">    *head = newNode;</span>
<span style="font-weight: 400">}</span>

// Function to delete a node from the circular doubly linked list

<span style="font-weight: 400">void deleteNode(struct Node** head, struct Node* nodeToDelete) {</span>
<span style="font-weight: 400">    if (*head == NULL)</span>
<span style="font-weight: 400">        return;</span>
 
<span style="font-weight: 400">    if (*head == nodeToDelete)</span>
<span style="font-weight: 400">        *head = (*head)->next;</span>
 
<span style="font-weight: 400">    nodeToDelete->prev->next = nodeToDelete->next;</span>
<span style="font-weight: 400">    nodeToDelete->next->prev = nodeToDelete->prev;</span>
 
<span style="font-weight: 400">    free(nodeToDelete);</span>
<span style="font-weight: 400">}</span>

// Function to traverse the circular doubly linked list

<span style="font-weight: 400">void traverseList(struct Node* head) {</span>
<span style="font-weight: 400">    if (head == NULL)</span>
<span style="font-weight: 400">        return;</span>
 
<span style="font-weight: 400">    struct Node* current = head;</span>
<span style="font-weight: 400">    do {</span>
<span style="font-weight: 400">        printf("%d ", current->data);</span>
<span style="font-weight: 400">        current = current->next;</span>
<span style="font-weight: 400">    } while (current != head);</span>
<span style="font-weight: 400">    printf("n");</span>
<span style="font-weight: 400">}</span>

// Function to search for a node with the given data in the circular doubly linked list

<span style="font-weight: 400">struct Node* searchList(struct Node* head, int searchKey) {</span>
<span style="font-weight: 400">    if (head == NULL)</span>
<span style="font-weight: 400">        return NULL;</span>
 
<span style="font-weight: 400">    struct Node* current = head;</span>
<span style="font-weight: 400">    do {</span>
<span style="font-weight: 400">        if (current->data == searchKey)</span>
<span style="font-weight: 400">            return current;</span>
<span style="font-weight: 400">        current = current->next;</span>
<span style="font-weight: 400">    } while (current != head);</span>
 
<span style="font-weight: 400">    return NULL;</span>
<span style="font-weight: 400">}</span>
 
<span style="font-weight: 400">int main() {</span>
<span style="font-weight: 400">    struct Node* head = NULL;</span>
<span style="font-weight: 400">    // You can add more code here...</span>
<span style="font-weight: 400">}</span>

// Insert nodes into the circular doubly linked list

<span style="font-weight: 400">insertNode(&head, createNode(1));</span>
<span style="font-weight: 400">insertNode(&head, createNode(2));</span>
<span style="font-weight: 400">insertNode(&head, createNode(3));</span>

// Traverse the circular doubly linked list

<span style="font-weight: 400">printf("The circular doubly linked list is: ");</span>
<span style="font-weight: 400">traverseList(head);</span>
 
<span style="font-weight: 400">// Delete a node from the circular doubly linked list</span>
<span style="font-weight: 400">struct Node* nodeToDelete = searchList(head, 2);</span>
<span style="font-weight: 400">deleteNode(&head, nodeToDelete);</span>

// Traverse the circular doubly linked list after deletion

<span style="font-weight: 400">printf("The circular doubly linked list after deletion is: ");</span>
<span style="font-weight: 400">traverseList(head);</span>
<span style="font-weight: 400">return 0;</span>
<span style="font-weight: 400">}</span>

Output:

________________________________________<br>
The circular doubly linked list is: 3 2 1<br>
The circular doubly linked list after deletion is: 3 1<br>
________________________________________<br>

Conclusion

To summarize, doubly linked lists are a strong data structure that provides rapid access to both the previous and next members in the list. They have various advantages over singly-linked lists, including simpler implementation of operations like deletion and insertion at random points in the list. Nevertheless, doubly-linked lists use more memory than singly-linked lists and may be less efficient in terms of space utilization.

Enhance your skills with our comprehensive C training and coding challenges!

Related Blogs What’s Inside
PyCharm Installation Outlines the process to install PyCharm for Python coding setups.
Spring Boot Interview Questions Features essential Spring Boot questions for Java developer interviews.
Variable and Constant in C Describes how variables and constants function in C programming.
JUnit Interview Questions Compiles JUnit interview questions for Java testing proficiency.
PyCharm Tutorial Explains PyCharm features for efficient Python development.
SOA Interview Questions Provides SOA questions to prepare for architecture-related interviews.
Keywords and Comments in C Explains C keywords and comments for structured programming.
C Installation Details steps to install a C programming environment on various systems.
Some Programs in C Shows sample C programs to teach fundamental programming techniques.
Mockito Annotations Outlines Mockito annotations for streamlined Java testing processes.

Our Data Science Courses Duration and Fees

Program Name
Start Date
Fees
Cohort Starts on: 8th Jun 2025
₹85,044

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.