×
>
<

Aptitude

Doubly Linked List

What is a doubly linked list

A Doubly Linked List is a unique type of Data Structure where there are a chain of nodes, that are connected to one another using pointers, where any individual node has 3 components –

  1. Data
  2. Previous Pointer
  3. Next Pointer

For any node, its previous pointer contains the address of the previous node and the next pointer contains the address of the next node in the chain of nodes.

Components in a Doubly Linked List

For writing Doubly Linked List Program in C we need to know that Doubly Linked List generally have the following components –

  • Node – A single unit in Doubly Linked List (DLL) contains – Data, previous and next pointers.
  • Next Pointer – Contains Address to next node
  • Previous Pointer – Contains Address to the previous node
  • Data – Stores the data value
  • Head – The first node in DLL

Some variations of DLL also have a tail node pointer, which signifies that this node is the end node in DLL.

Note : The next pointer of the last node points to NULL and previous pointer of the first node points to NULL as well

Why doubly linked list?

Unlike singly Linked List, which only traverses in one direction. Doubly Linked List can traverse both in forwards and backwards direction.

As for any given node, we have both previous and next node addresses information available.

You can moves in any direction in doubly linked list because of the presence of multiple pointer in it. This is one of the biggest advantage of using doubly linked list.

Insertion operation in doubly linked list

Following insertion operation can be performed on a doubly linked list.

  1. Insertion at beginning
  2. Insertion at end
  3. Insertion in between of nodes

Doubly Linked List Operations

  • Create a new node
  • Assign its data value
  • Assign newly created node’s next ptr to current head reference. So, it points to the previous start node of the linked list address
  • Assign newly created node’s previous node to NULL
  • Assign the current head’s previous node to this new node
  • Change the head reference to the new node’s address.

Doubly Linked List Insertion at the end

Algorithm of insertion at the end

  • Create a new node
  • Assign its data value
  • Traverse till the end of the Linked List call this node temp
  • Assign newly created node’s next node to NULL
  • Assign newly created node’s previous node to temp
  • Assign Temp’s next node to this newly created node.

Image Name ???
Doubly Linked List Insertion after a position

Algorithm of insertion after a position

  • Create a new node
  • Assign its data value
  • Traverse till nth(pos) node lets call this temp
  • Assign newly created node’s next node to temp’s next node
  • Assign newly created node’s previous node to temp
  • Assign Temp’s next node to this newly created node.

Insertion at nth postion
Code of Doubly Linked List
  
#include<stdio.h>
#include<stdlib.h>

struct Node { 
    int data;
    struct Node *next;
    struct Node *prev;
};
void insertStart(struct Node** head, int data){
    
    // creating memory for newNode
    struct Node* newNode = (struct Node*) malloc(sizeof(struct Node));
    
    // assigning newNode's next as the current head 
    // Assign data & and make newNode's prev as NULL
    newNode->data = data;
    newNode->next = *head;
    newNode->prev = NULL;
    
    // if list already had item(s)
    // We need to make current head previous node as this new node
    if(*head != NULL)
        (*head)->prev = newNode;
    
    // change head to this newNode
    *head = newNode;
    
}
void display(struct Node* node)
{
    struct Node* end;
    printf("\nIn Forward Direction\n");
    while (node != NULL) {
        printf(" %d ", node->data);
        end = node;
        node = node->next;
    }
 
    printf("\nIn Backward direction \n");
    while (end != NULL) {
        printf(" %d ", end->data);
        end = end->prev;
    }
}
int main()
{
    struct Node* head = NULL;
    
    // Need '&' i.e. address as we need to change head
    insertStart(&head,1);
    insertStart(&head,2);
    insertStart(&head,3);
    
    // no need for '&' as head need not be changed
    // only doing traversal
    display(head);
    
    return 0;
}
  
  
  
#include<iostream>
#include<stdlib.h>



using namespace std;

// node creation
struct Node {
  int data;
  struct Node* next;
  struct Node* prev;
};

// insert node at the front
void insertFront(struct Node** head, int data) {
  // allocate memory for newNode
  struct Node* newNode = new Node;

  // assign data to newNode
  newNode->data = data;

  // make newNode as a head
  newNode->next = (*head);

  // assign null to prev
  newNode->prev = NULL;

  // previous of head (now head is the second node) is newNode
  if ((*head) != NULL)
    (*head)->prev = newNode;

  // head points to newNode
  (*head) = newNode;
}

// insert a node after a specific node
void insertAfter(struct Node* prev_node, int data) {
  // check if previous node is null
  if (prev_node == NULL) {
    cout << "previous node cannot be null";
    return;
  }

  // allocate memory for newNode
  struct Node* newNode = new Node;

  // assign data to newNode
  newNode->data = data;

  // set next of newNode to next of prev node
  newNode->next = prev_node->next;

  // set next of prev node to newNode
  prev_node->next = newNode;

  // set prev of newNode to the previous node
  newNode->prev = prev_node;

  // set prev of newNode's next to newNode
  if (newNode->next != NULL)
    newNode->next->prev = newNode;
}

// insert a newNode at the end of the list
void insertEnd(struct Node** head, int data) {
  // allocate memory for node
  struct Node* newNode = new Node;

  // assign data to newNode
  newNode->data = data;

  // assign null to next of newNode
  newNode->next = NULL;

  // store the head node temporarily (for later use)
  struct Node* temp = *head;

  // if the linked list is empty, make the newNode as head node
  if (*head == NULL) {
    newNode->prev = NULL;
    *head = newNode;
    return;
  }

  // if the linked list is not empty, traverse to the end of the linked list
  while (temp->next != NULL)
    temp = temp->next;

  // now, the last node of the linked list is temp

  // assign next of the last node (temp) to newNode
  temp->next = newNode;

  // assign prev of newNode to temp
  newNode->prev = temp;
}

// delete a node from the doubly linked list
void deleteNode(struct Node** head, struct Node* del_node) {
  // if head or del is null, deletion is not possible
  if (*head == NULL || del_node == NULL)
    return;

  // if del_node is the head node, point the head pointer to the next of del_node
  if (*head == del_node)
    *head = del_node->next;

  // if del_node is not at the last node, point the prev of node next to del_node to the previous of del_node
  if (del_node->next != NULL)
    del_node->next->prev = del_node->prev;

  // if del_node is not the first node, point the next of the previous node to the next node of del_node
  if (del_node->prev != NULL)
    del_node->prev->next = del_node->next;

  // free the memory of del_node
  free(del_node);
}

// print the doubly linked list
void displayList(struct Node* node) {
  struct Node* last;

  while (node != NULL) {
    cout << node->data << "->";
    last = node;
    node = node->next;
  }
  if (node == NULL)
    cout << "NULL\n";
}

int main() {
  // initialize an empty node
  struct Node* head = NULL;

  insertEnd(&head, 5);
  insertFront(&head, 1);
  insertFront(&head, 6);
  insertEnd(&head, 9);

  // insert 11 after head
  insertAfter(head, 11);

  // insert 15 after the seond node
  insertAfter(head->next, 15);

  displayList(head);

  // delete the last node
  deleteNode(&head, head->next->next->next->next->next);

  displayList(head);
}
int main()
{
    int n,a;
    starrt_node = NULL;
    end_node = NULL;
             
    cout<<"  Enter the number of nodes: ";
    cin>>n;
    Listcreation(n); 
    a=1;
    display(a);
    return 0;
}
  
  
public class DoublyLinkedList {

  // node creation
  Node head;

  class Node {
    int data;
    Node prev;
    Node next;

    Node(int d) {
      data = d;
    }
  }

  // insert node at the front
  public void insertFront(int data) {
    // allocate memory for newNode and assign data to newNode
    Node newNode = new Node(data);

    // make newNode as a head
    newNode.next = head;

    // assign null to prev of newNode
    newNode.prev = null;

    // previous of head (now head is the second node) is newNode
    if (head != null)
      head.prev = newNode;

    // head points to newNode
    head = newNode;
  }

  // insert a node after a specific node
  public void insertAfter(Node prev_node, int data) {

    // check if previous node is null
    if (prev_node == null) {
      System.out.println("previous node cannot be null");
      return;
    }

    // allocate memory for newNode and assign data to newNode
    Node new_node = new Node(data);

    // set next of newNode to next of prev node
    new_node.next = prev_node.next;

    // set next of prev node to newNode
    prev_node.next = new_node;

    // set prev of newNode to the previous node
    new_node.prev = prev_node;

    // set prev of newNode's next to newNode
    if (new_node.next != null)
      new_node.next.prev = new_node;
  }

  // insert a newNode at the end of the list
  void insertEnd(int data) {
    // allocate memory for newNode and assign data to newNode
    Node new_node = new Node(data);

    // store the head node temporarily (for later use)
    Node temp = head;

    // assign null to next of newNode
    new_node.next = null;

    // if the linked list is empty, make the newNode as head node
    if (head == null) {
      new_node.prev = null;
      head = new_node;
      return;
    }

    // if the linked list is not empty, traverse to the end of the linked list
    while (temp.next != null)
      temp = temp.next;

    // assign next of the last node (temp) to newNode
    temp.next = new_node;

    // assign prev of newNode to temp
    new_node.prev = temp;
  }

  // delete a node from the doubly linked list
  void deleteNode(Node del_node) {

    // if head or del is null, deletion is not possible
    if (head == null || del_node == null) {
      return;
    }

    // if del_node is the head node, point the head pointer to the next of del_node
    if (head == del_node) {
      head = del_node.next;
    }

    // if del_node is not at the last node, point the prev of node next to del_node
    // to the previous of del_node
    if (del_node.next != null) {
      del_node.next.prev = del_node.prev;
    }

    // if del_node is not the first node, point the next of the previous node to the
    // next node of del_node
    if (del_node.prev != null) {
      del_node.prev.next = del_node.next;
    }

  }

  // print the doubly linked list
  public void printlist(Node node) {
    Node last = null;
    while (node != null) {
      System.out.print(node.data + "->");
      last = node;
      node = node.next;
    }
    System.out.println();
  }

  public static void main(String[] args) {
    DoublyLinkedList doubly_ll = new DoublyLinkedList();

    doubly_ll.insertEnd(50);
    doubly_ll.insertFront(10);
    doubly_ll.insertFront(65);
    doubly_ll.insertEnd(93);

    // insert 11 after head
    doubly_ll.insertAfter(doubly_ll.head, 12);

    // insert 15 after the seond node
    doubly_ll.insertAfter(doubly_ll.head.next, 12);

    doubly_ll.printlist(doubly_ll.head);

    // delete the last node
    doubly_ll.deleteNode(doubly_ll.head.next.next.next.next.next);

    doubly_ll.printlist(doubly_ll.head);
  }
}
	

Output : C

	
In Forward Direction
 3  2  1 
In Backward direction 
 1  2  3 
	

Output : C++

	
6->11->15->1->5->9->NULL
6->11->15->1->5->NULL
	

Output : Java

	
65->12->12->10->50->93->
65->12->12->10->50->
	
Some Points about
Advantages of using doubly linked list in C

  1. It saves time as we can traverse in both directions.
  2. It utilizes memory as we can construct and delete nodes according to our needs.
  3. Insertion and deletion of the node become efficient if the position is given.

Disadvantages of using doubly linked list in C

  1. Uses more memory per node.
  2. Insertion and deletion take more time because extra pointers need to be maintained.