A Doubly Linked List (DLL) is a type of linked data structure that consists of nodes. Each node contains three parts: the data, a pointer to the next node, and a pointer to the previous node. This bidirectional nature makes DLLs more versatile compared to Singly Linked Lists (SLL), as they can be traversed in both directions. In this guide, we will explore in detail the different techniques for inserting a new node in a Doubly Linked List.
Table of Contents
Introduction to Insertion in Doubly Linked List
Insertion in a Doubly Linked List involves linking a new node with its adjacent nodes. This requires updating both the next
and prev
pointers of the new node and the affected nodes. While similar to insertion in a Singly Linked List, the added step of managing the prev
pointer makes it slightly more complex.
We will cover the following types of insertions in detail:
- Insertion at the Beginning
- Insertion After a Given Node
- Insertion Before a Given Node
- Insertion at a Specific Position
- Insertion at the End
1. Insertion at the Beginning
Inserting a new node at the start of a Doubly Linked List is the simplest form of insertion. Here’s how it works:
Steps for Insertion
- Create a New Node:
Allocate memory for the new node, initialize it with data, and set itsprev
pointer to NULL (as it will be the first node in the list). - Link the New Node to the Current Head:
Update thenext
pointer of the new node to point to the current head of the list:new_node->next = head
. - Update the Head Node’s Previous Pointer (if Applicable):
If the list is not empty, the current head node’sprev
pointer needs to be updated to point to the new node:head->prev = new_node
. - Update the Head of the List:
Finally, set the new node as the head of the list.
Example
Consider a list with nodes {10 <-> 20 <-> 30}
and a new node 5
to be inserted. After insertion, the list becomes {5 <-> 10 <-> 20 <-> 30}
.
Implementation In Multiple Programming Languages

Here is the code written in C, C++, C#, Java, JavaScript, and Python, along with a detailed step-by-step explanation for each language.
C Implementation
#include <stdio.h>
#include <stdlib.h>
// Define the structure of a doubly linked list node
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
// Function to create a new node
struct Node *createNode(int new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// Function to insert a new node at the front of the doubly linked list
struct Node *insertAtFront(struct Node *head, int new_data) {
struct Node *new_node = createNode(new_data);
new_node->next = head;
if (head != NULL) {
head->prev = new_node;
}
return new_node;
}
// Function to print the doubly linked list
void printList(struct Node *head) {
struct Node *curr = head;
while (curr != NULL) {
printf(" %d", curr->data);
curr = curr->next;
}
printf("\n");
}
int main() {
// Create a doubly linked list: 2 <-> 3 <-> 4
struct Node *head = createNode(2);
head->next = createNode(3);
head->next->prev = head;
head->next->next = createNode(4);
head->next->next->prev = head->next;
// Print the original list
printf("Original Linked List:");
printList(head);
// Insert a new node at the front of the list
printf("After inserting Node at the front:");
int data = 1;
head = insertAtFront(head, data);
// Print the updated list
printList(head);
return 0;
}
Explanation
- Structure Definition:
- The
Node
structure contains three fields:data
(to store the value),next
(pointer to the next node), andprev
(pointer to the previous node). - It allows bidirectional traversal.
- The
- Creating Nodes:
- The
createNode
function allocates memory for a new node and initializes itsdata
,next
, andprev
fields.
- The
- Insertion Logic:
- In
insertAtFront
, the new node is created and itsnext
is linked to the current head. - If the list is non-empty, the
prev
pointer of the current head is updated to point to the new node. - Finally, the new node is returned as the updated head of the list.
- In
- Printing the List:
- The
printList
function traverses the list using thenext
pointer and prints thedata
of each node.
- The
- Main Function:
- A hardcoded list
(2 <-> 3 <-> 4)
is created. - A new node with data
1
is inserted at the front, updating the head pointer. - Both the original and updated lists are printed.
- A hardcoded list
C++ Implementation
#include <iostream>
using namespace std;
// Node structure
struct Node {
int data;
Node* next;
Node* prev;
Node(int new_data) : data(new_data), next(nullptr), prev(nullptr) {}
};
// Function to insert at the front
Node* insertAtFront(Node* head, int new_data) {
Node* new_node = new Node(new_data);
new_node->next = head;
if (head != nullptr) {
head->prev = new_node;
}
return new_node;
}
// Function to print the list
void printList(Node* head) {
Node* curr = head;
while (curr != nullptr) {
cout << " " << curr->data;
curr = curr->next;
}
cout << endl;
}
int main() {
// Create a doubly linked list: 2 <-> 3 <-> 4
Node* head = new Node(2);
head->next = new Node(3);
head->next->prev = head;
head->next->next = new Node(4);
head->next->next->prev = head->next;
// Print the original list
cout << "Original Linked List:";
printList(head);
// Insert a new node at the front
cout << "After inserting Node at the front:";
int data = 1;
head = insertAtFront(head, data);
// Print the updated list
printList(head);
return 0;
}
C# Implementation
using System;
class Node {
public int data;
public Node next;
public Node prev;
public Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
// Insert at the front
public static Node InsertAtFront(Node head, int newData) {
Node newNode = new Node(newData);
newNode.next = head;
if (head != null) {
head.prev = newNode;
}
return newNode;
}
// Print the list
public static void PrintList(Node head) {
Node curr = head;
while (curr != null) {
Console.Write(" " + curr.data);
curr = curr.next;
}
Console.WriteLine();
}
static void Main() {
// Create a doubly linked list: 2 <-> 3 <-> 4
Node head = new Node(2);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
Console.WriteLine("Original Linked List:");
PrintList(head);
// Insert a new node at the front
Console.WriteLine("After inserting Node at the front:");
int data = 1;
head = InsertAtFront(head, data);
// Print the updated list
PrintList(head);
}
}
Java Implementation
class Node {
int data;
Node next, prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
public class DoublyLinkedList {
// Insert at the front
static Node insertAtFront(Node head, int newData) {
Node newNode = new Node(newData);
newNode.next = head;
if (head != null) {
head.prev = newNode;
}
return newNode;
}
// Print the list
static void printList(Node head) {
Node curr = head;
while (curr != null) {
System.out.print(" " + curr.data);
curr = curr.next;
}
System.out.println();
}
public static void main(String[] args) {
// Create a doubly linked list: 2 <-> 3 <-> 4
Node head = new Node(2);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
System.out.println("Original Linked List:");
printList(head);
// Insert a new node at the front
System.out.println("After inserting Node at the front:");
int data = 1;
head = insertAtFront(head, data);
// Print the updated list
printList(head);
}
}
JavaScript Implementation
class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
// Insert at the front
static insertAtFront(head, newData) {
const newNode = new Node(newData);
newNode.next = head;
if (head !== null) {
head.prev = newNode;
}
return newNode;
}
// Print the list
static printList(head) {
let curr = head;
while (curr !== null) {
process.stdout.write(" " + curr.data);
curr = curr.next;
}
console.log();
}
}
// Main execution
let head = new Node(2);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
console.log("Original Linked List:");
DoublyLinkedList.printList(head);
// Insert a new node at the front
console.log("After inserting Node at the front:");
head = DoublyLinkedList.insertAtFront(head, 1);
// Print the updated list
DoublyLinkedList.printList(head);
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class DoublyLinkedList:
@staticmethod
def insert_at_front(head, new_data):
new_node = Node(new_data)
new_node.next = head
if head is not None:
head.prev = new_node
return new_node
@staticmethod
def print_list(head):
curr = head
while curr:
print(curr.data, end=" ")
curr = curr.next
print()
# Main execution
# Create a doubly linked list: 2 <-> 3 <-> 4
head = Node(2)
head.next = Node(3)
head.next.prev = head
head.next.next = Node(4)
head.next.next.prev = head.next
# Print the original list
print("Original Linked List:")
DoublyLinkedList.print_list(head)
# Insert a new node at the front
print("After inserting Node at the front:")
head = DoublyLinkedList.insert_at_front(head, 1)
# Print the updated list
DoublyLinkedList.print_list(head)
Output across all languages:
Original Linked List: 2 3 4
After inserting Node at the front: 1 2 3 4
Time Complexity: O(1)
Auxiliary Space: O(1)
2. Insertion After a Given Node
To insert a new node after a specific node in a Doubly Linked List, follow these steps:
Steps for Insertion
- Locate the Node:
Traverse the list to find the node after which the new node is to be inserted. Let this node be calledcurr
. - Create a New Node:
Allocate memory for the new node and initialize it with data. Set itsprev
pointer tocurr
. - Link the New Node to the Next Node:
Update thenext
pointer of the new node to point to the node aftercurr
:new_node->next = curr->next
. - Update the Current Node’s Next Pointer:
Changecurr->next
to point to the new node. - Update the Next Node’s Previous Pointer (if Applicable):
If the new node is not the last node, update theprev
pointer of the next node to point back to the new node:new_node->next->prev = new_node
.
Example
Given the list {10 <-> 20 <-> 30}
and inserting 25
after 20
, the result will be {10 <-> 20 <-> 25 <-> 30}
.
Implementation In Multiple Programming Languages

Here is the code written in C, C++, C#, Java, JavaScript, and Python, along with a detailed step-by-step explanation for each language.
C Implementation
#include <stdio.h>
#include <stdlib.h>
// Define the structure of a doubly linked list node
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
// Function to create a new node with the given data
struct Node *createNode(int new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// Function to insert a new node after a given node
struct Node *insertAfter(struct Node *head, int key, int new_data) {
struct Node *curr = head;
// Traverse the list to find the node with the given key
while (curr != NULL) {
if (curr->data == key)
break;
curr = curr->next;
}
// If key is not found, return the original head
if (curr == NULL)
return head;
// Create a new node
struct Node *new_node = createNode(new_data);
// Update links to insert the new node
new_node->prev = curr;
new_node->next = curr->next;
// Update the next pointer of the current node
curr->next = new_node;
// Update the previous pointer of the new node's next
if (new_node->next != NULL)
new_node->next->prev = new_node;
return head;
}
// Function to print the doubly linked list
void printList(struct Node *head) {
struct Node *curr = head;
while (curr != NULL) {
printf(" %d", curr->data);
curr = curr->next;
}
printf("\n");
}
int main() {
// Create a doubly linked list: 1 <-> 3 <-> 4
struct Node *head = createNode(1);
head->next = createNode(3);
head->next->prev = head;
head->next->next = createNode(4);
head->next->next->prev = head->next;
// Print the original list
printf("Original Linked List:");
printList(head);
// Insert a new node after node with key 1
printf("Inserting Node with data 2 after node 1 :");
head = insertAfter(head, 1, 2);
// Print the updated list
printList(head);
return 0;
}
Step by Step Explanation
- Structure Definition:
- The
Node
structure has three fields:data
: Stores the value.next
: Points to the next node in the list.prev
: Points to the previous node.
- The
createNode
Function:- Allocates memory for a new node.
- Initializes
data
,next
, andprev
.
insertAfter
Function:- Traverses the list to find the node with the given key.
- If the key is found, creates a new node and updates:
prev
of the new node to point to the current node.next
of the new node to point to the current node’s next.
- Updates the
next
pointer of the current node to point to the new node. - Updates the
prev
pointer of the next node (if it exists) to point back to the new node.
- Printing Function:
- Traverses the list and prints
data
of each node.
- Traverses the list and prints
- Main Function:
- Creates a doubly linked list:
1 <-> 3 <-> 4
. - Inserts
2
after1
. - Prints both the original and updated lists.
- Creates a doubly linked list:
C++ Implementation
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node* prev;
Node(int new_data) : data(new_data), next(nullptr), prev(nullptr) {}
};
// Function to insert a node after a given node
Node* insertAfter(Node* head, int key, int new_data) {
Node* curr = head;
// Traverse to find the key
while (curr) {
if (curr->data == key)
break;
curr = curr->next;
}
// If key is not found, return the original head
if (!curr)
return head;
// Create new node and update links
Node* new_node = new Node(new_data);
new_node->prev = curr;
new_node->next = curr->next;
curr->next = new_node;
if (new_node->next)
new_node->next->prev = new_node;
return head;
}
// Function to print the list
void printList(Node* head) {
Node* curr = head;
while (curr) {
cout << " " << curr->data;
curr = curr->next;
}
cout << endl;
}
int main() {
// Create a doubly linked list: 1 <-> 3 <-> 4
Node* head = new Node(1);
head->next = new Node(3);
head->next->prev = head;
head->next->next = new Node(4);
head->next->next->prev = head->next;
// Print the original list
cout << "Original Linked List:";
printList(head);
// Insert a new node after node with key 1
cout << "Inserting Node with data 2 after node 1 :";
head = insertAfter(head, 1, 2);
// Print the updated list
printList(head);
return 0;
}
Step by Step Explanation
- Structure Definition:
- The
Node
structure has three fields:data
: Stores the value.next
: Points to the next node in the list.prev
: Points to the previous node.
- The
createNode
Function:- Allocates memory for a new node.
- Initializes
data
,next
, andprev
.
insertAfter
Function:- Traverses the list to find the node with the given key.
- If the key is found, creates a new node and updates:
prev
of the new node to point to the current node.next
of the new node to point to the current node’s next.
- Updates the
next
pointer of the current node to point to the new node. - Updates the
prev
pointer of the next node (if it exists) to point back to the new node.
- Printing Function:
- Traverses the list and prints
data
of each node.
- Traverses the list and prints
- Main Function:
- Creates a doubly linked list:
1 <-> 3 <-> 4
. - Inserts
2
after1
. - Prints both the original and updated lists.
- Creates a doubly linked list:
C# Implementation
using System;
class Node {
public int data;
public Node next;
public Node prev;
public Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
public Node InsertAfter(Node head, int key, int newData) {
Node current = head;
// Traverse the list to find the key
while (current != null) {
if (current.data == key)
break;
current = current.next;
}
// If key is not found, return the original head
if (current == null) return head;
// Create a new node
Node newNode = new Node(newData);
// Update links to insert the new node
newNode.prev = current;
newNode.next = current.next;
if (current.next != null)
current.next.prev = newNode;
current.next = newNode;
return head;
}
public void PrintList(Node head) {
Node current = head;
while (current != null) {
Console.Write(" " + current.data);
current = current.next;
}
Console.WriteLine();
}
}
class Program {
static void Main(string[] args) {
DoublyLinkedList dll = new DoublyLinkedList();
// Create a doubly linked list: 1 <-> 3 <-> 4
Node head = new Node(1);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
Console.WriteLine("Original Linked List:");
dll.PrintList(head);
// Insert a new node after node with key 1
Console.WriteLine("Inserting Node with data 2 after node 1 :");
head = dll.InsertAfter(head, 1, 2);
// Print the updated list
dll.PrintList(head);
}
}
Explanation
- Class
Node
:- Defines a doubly linked list node with
data
,next
, andprev
properties.
- Defines a doubly linked list node with
- Class
DoublyLinkedList
:- Contains the method
InsertAfter
to insert a new node after a specific key. - Updates the links (
next
andprev
) of the nodes involved.
- Contains the method
InsertAfter
Method:- Traverses the list to find the key.
- If the key is found:
- Creates a new node.
- Updates the pointers of the current node and the new node.
- Updates the
prev
pointer of the new node’s next node, if it exists.
- Printing Method:
- Traverses the list from the head, printing each node’s
data
.
- Traverses the list from the head, printing each node’s
Main
Method:- Creates a doubly linked list with hardcoded values.
- Inserts a node with
data = 2
afterdata = 1
. - Prints the original and updated lists.
Java Implementation
class Node {
int data;
Node next;
Node prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
// Method to insert a new node after a given key
Node insertAfter(Node head, int key, int newData) {
Node current = head;
// Traverse to find the key
while (current != null) {
if (current.data == key)
break;
current = current.next;
}
// If key is not found, return the original head
if (current == null) return head;
// Create a new node
Node newNode = new Node(newData);
// Update links
newNode.prev = current;
newNode.next = current.next;
if (current.next != null)
current.next.prev = newNode;
current.next = newNode;
return head;
}
// Method to print the list
void printList(Node head) {
Node current = head;
while (current != null) {
System.out.print(" " + current.data);
current = current.next;
}
System.out.println();
}
}
public class Main {
public static void main(String[] args) {
DoublyLinkedList dll = new DoublyLinkedList();
// Create a doubly linked list: 1 <-> 3 <-> 4
Node head = new Node(1);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
System.out.println("Original Linked List:");
dll.printList(head);
// Insert a new node after node with key 1
System.out.println("Inserting Node with data 2 after node 1 :");
head = dll.insertAfter(head, 1, 2);
// Print the updated list
dll.printList(head);
}
}
Step-by-Step Explanation
1. Node
Class
The Node
class represents each node in the doubly linked list.
- Attributes:
data
: Stores the integer data for the node.next
: Points to the next node in the list.prev
: Points to the previous node in the list.
- Constructor:
- Initializes the
data
attribute with the given value. - Sets
next
andprev
pointers tonull
.
- Initializes the
2. DoublyLinkedList
Class
(a.) insertAfter
Method
- Input Parameters:
Node head
: The head node of the doubly linked list.int key
: The value after which the new node will be inserted.int newData
: The data for the new node.
- Traversal:
- Starts traversing the list from the
head
using a pointer (current
). - Compares the
data
of each node withkey
until it finds the node with thekey
or reaches the end of the list.
- Starts traversing the list from the
- If
key
Is Not Found:- If the traversal completes without finding the key (
current == null
), the method returns the original list without making any changes.
- If the traversal completes without finding the key (
- Node Creation:
- Creates a new
Node
object, passingnewData
to its constructor.
- Creates a new
- Updating Links:
- Sets
newNode.prev = current
(points the new node’sprev
to the node containing thekey
). - Sets
newNode.next = current.next
(points the new node’snext
to the node that follows thecurrent
node). - If
current.next
exists, updates itsprev
pointer to thenewNode
. - Updates
current.next
to point tonewNode
, effectively inserting the new node after thecurrent
node.
- Sets
(b.) printList
Method
- Traversal:
- Starts at the
head
node and iterates through the list. - Prints the
data
of each node until the end of the list is reached.
- Starts at the
3. Main
Class
- Creating the Doubly Linked List:
- Constructs a hardcoded list:
1 <-> 3 <-> 4
. - Manually links the
next
andprev
pointers for each node.
- Constructs a hardcoded list:
- Printing the Original List:
- Calls the
printList
method to display the initial list.
- Calls the
- Inserting a New Node:
- Calls the
insertAfter
method to insert a node withdata = 2
after the node withdata = 1
.
- Calls the
- Printing the Updated List:
- Calls the
printList
method to display the modified list.
- Calls the
JavaScript Implementation
class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
insertAfter(head, key, newData) {
let current = head;
// Traverse to find the key
while (current) {
if (current.data === key) break;
current = current.next;
}
// If key is not found, return the original head
if (!current) return head;
// Create a new node
const newNode = new Node(newData);
// Update links
newNode.prev = current;
newNode.next = current.next;
if (current.next) current.next.prev = newNode;
current.next = newNode;
return head;
}
printList(head) {
let current = head;
let result = [];
while (current) {
result.push(current.data);
current = current.next;
}
console.log(result.join(" "));
}
}
// Create a doubly linked list: 1 <-> 3 <-> 4
const dll = new DoublyLinkedList();
let head = new Node(1);
head.next = new Node(3);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
// Print the original list
console.log("Original Linked List:");
dll.printList(head);
// Insert a new node after node with key 1
console.log("Inserting Node with data 2 after node 1 :");
head = dll.insertAfter(head, 1, 2);
// Print the updated list
dll.printList(head);
Step-by-Step Explanation
1. Node
Class
The Node
class represents a node in the doubly linked list.
- Attributes:
data
: Stores the value of the node.next
: Points to the next node in the list.prev
: Points to the previous node in the list.
- Constructor:
- Accepts the
data
and initializes thenext
andprev
pointers asnull
.
- Accepts the
2. DoublyLinkedList
Class
(a.) insertAfter
Method
- Input Parameters:
head
: The head node of the doubly linked list.key
: The value after which the new node will be inserted.newData
: The data for the new node.
- Traversal:
- Uses a variable
current
to traverse the list from thehead
. - Checks if the
data
of each node matches thekey
.
- Uses a variable
- If
key
Is Not Found:- If the traversal completes and the
key
is not found (current === null
), the method returns the original list unchanged.
- If the traversal completes and the
- Node Creation:
- Creates a new
Node
object, passingnewData
to its constructor.
- Creates a new
- Updating Links:
- Sets
newNode.prev = current
(points the new node’sprev
to the node containing thekey
). - Sets
newNode.next = current.next
(points the new node’snext
to the node following thecurrent
node). - If
current.next
exists, updates itsprev
pointer to thenewNode
. - Updates
current.next
to point tonewNode
, inserting the new node after thecurrent
node.
- Sets
b. printList
Method
- Traversal:
- Starts from the
head
and iterates through the list. - Stores the
data
of each node in an array. - Joins the array into a string and prints the result.
- Starts from the
3. Main Program
- Creating the Doubly Linked List:
- Constructs a list:
1 <-> 3 <-> 4
. - Manually sets the
next
andprev
pointers for each node.
- Constructs a list:
- Printing the Original List:
- Calls the
printList
method to display the initial list.
- Calls the
- Inserting a New Node:
- Calls the
insertAfter
method to insert a node withdata = 2
after the node withdata = 1
.
- Calls the
- Printing the Updated List:
- Calls the
printList
method to display the modified list.
- Calls the
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class DoublyLinkedList:
# Function to insert a new node after a given key
def insert_after(self, head, key, new_data):
current = head
# Traverse to find the key
while current:
if current.data == key:
break
current = current.next
# If key is not found, return the original head
if not current:
return head
# Create a new node
new_node = Node(new_data)
# Update links
new_node.prev = current
new_node.next = current.next
if current.next:
current.next.prev = new_node
current.next = new_node
return head
# Function to print the list
def print_list(self, head):
current = head
while current:
print(current.data, end=" ")
current = current.next
print()
# Create a doubly linked list: 1 <-> 3 <-> 4
dll = DoublyLinkedList()
head = Node(1)
head.next = Node(3)
head.next.prev = head
head.next.next = Node(4)
head.next.next.prev = head.next
# Print the original list
print("Original Linked List:")
dll.print_list(head)
# Insert a new node after node with key 1
print("Inserting Node with data 2 after node 1:")
head = dll.insert_after(head, 1, 2)
# Print the updated list
dll.print_list(head)
Step-by-Step Explanation
(1.) Node Class
- Purpose: Represents each node in the doubly linked list.
- Attributes:
data
: Stores the data for the node.next
: Points to the next node in the list.prev
: Points to the previous node in the list.
- Initialization: The
__init__
constructor initializes thedata
,next
, andprev
pointers toNone
.
(2.) DoublyLinkedList Class
- This class contains utility methods for the doubly linked list.
(a.) insert_after
Method
- Input Parameters:
head
: The head node of the doubly linked list.key
: The value after which the new node is to be inserted.new_data
: The data of the new node.
- Traversal:
- Starts from the
head
and traverses through the list to locate the node containing thekey
. - If the
key
is not found (current
becomesNone
), it returns the original list without any modification.
- Starts from the
- Node Creation:
- A new node is created with
new_data
.
- A new node is created with
- Updating Links:
new_node.prev
is set tocurrent
(the node containing the key).new_node.next
is set tocurrent.next
.- If
current.next
exists, itsprev
is updated to point tonew_node
. - Finally,
current.next
is updated to point tonew_node
.
(b.) print_list
Method
- Traverses the list starting from the
head
and prints thedata
of each node until the end of the list.
(3.) Main Program
- List Creation:
- Creates a hardcoded doubly linked list:
1 <-> 3 <-> 4
. - Links are established manually for the
next
andprev
pointers of the nodes.
- Creates a hardcoded doubly linked list:
- Print the Original List:
- Calls the
print_list
method to display the list.
- Calls the
- Insert New Node:
- Calls the
insert_after
method to insert a node withdata = 2
after the node withdata = 1
.
- Calls the
- Print the Updated List:
- Prints the modified list to confirm the insertion.
Output
Original Linked List:
1 3 4
Inserting Node with data 2 after node 1:
1 2 3 4
Time Complexity: O(n), where n is the number of nodes in the doubly linked list
Auxiliary Space: O(1)
3. Insertion Before a Given Node
Inserting a node before a specific node is another common operation. Here’s how it’s done:
Steps for Insertion
- Locate the Node:
Traverse the list to find the node before which the new node is to be inserted. Let this node be calledcurr
. - Create a New Node:
Allocate memory for the new node, initialize it with data, and set itsnext
pointer tocurr
. - Link the New Node to the Previous Node:
Update theprev
pointer of the new node to point to the node beforecurr
:new_node->prev = curr->prev
. - Update the Previous Node’s Next Pointer (if Applicable):
Ifcurr
is not the head of the list, update thenext
pointer ofcurr->prev
to point to the new node:new_node->prev->next = new_node
. - Update the Current Node’s Previous Pointer:
Finally, update theprev
pointer ofcurr
to point to the new node:curr->prev = new_node
.
Example
For the list {10 <-> 20 <-> 30}
and inserting 15
before 20
, the result will be {10 <-> 15 <-> 20 <-> 30}
.
Implementation In Multiple Programming Languages

Here is the code written in C, C++, C#, Java, JavaScript, and Python, along with a detailed step-by-step explanation for each language.
C Program Implementation
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
// Function to create a new node with the given data
struct Node *createNode(int new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// Function to insert a new node before a given node
struct Node* insertBefore(struct Node *head, int key, int new_data) {
struct Node *curr = head;
while (curr != NULL) {
if (curr->data == key) break;
curr = curr->next;
}
if (curr == NULL) return head; // Key not found
struct Node *new_node = createNode(new_data);
new_node->prev = curr->prev;
new_node->next = curr;
if (curr->prev != NULL) {
curr->prev->next = new_node;
} else {
head = new_node;
}
curr->prev = new_node;
return head;
}
void printList(struct Node *head) {
struct Node *curr = head;
while (curr != NULL) {
printf(" %d", curr->data);
curr = curr->next;
}
printf("\n");
}
int main() {
struct Node *head = createNode(1);
head->next = createNode(3);
head->next->prev = head;
head->next->next = createNode(4);
head->next->next->prev = head->next;
printf("Original Linked List:");
printList(head);
printf("Inserting Node with data 2 before node 3:");
head = insertBefore(head, 3, 2);
printList(head);
return 0;
}
C++ Implementation
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int new_data) {
data = new_data;
next = nullptr;
prev = nullptr;
}
};
class DoublyLinkedList {
public:
Node* head;
DoublyLinkedList() {
head = nullptr;
}
void insertBefore(int key, int new_data) {
Node* curr = head;
while (curr != nullptr) {
if (curr->data == key) break;
curr = curr->next;
}
if (curr == nullptr) return;
Node* new_node = new Node(new_data);
new_node->prev = curr->prev;
new_node->next = curr;
if (curr->prev != nullptr) {
curr->prev->next = new_node;
} else {
head = new_node;
}
curr->prev = new_node;
}
void printList() {
Node* curr = head;
while (curr != nullptr) {
cout << " " << curr->data;
curr = curr->next;
}
cout << endl;
}
};
int main() {
DoublyLinkedList list;
list.head = new Node(1);
list.head->next = new Node(3);
list.head->next->prev = list.head;
list.head->next->next = new Node(4);
list.head->next->next->prev = list.head->next;
cout << "Original Linked List:";
list.printList();
cout << "Inserting Node with data 2 before node 3:";
list.insertBefore(3, 2);
list.printList();
return 0;
}
C# Implementation
using System;
class Node {
public int Data;
public Node Next;
public Node Prev;
public Node(int data) {
Data = data;
Next = null;
Prev = null;
}
}
class DoublyLinkedList {
public Node Head;
public void InsertBefore(int key, int newData) {
Node curr = Head;
while (curr != null) {
if (curr.Data == key) break;
curr = curr.Next;
}
if (curr == null) return;
Node newNode = new Node(newData);
newNode.Prev = curr.Prev;
newNode.Next = curr;
if (curr.Prev != null) {
curr.Prev.Next = newNode;
} else {
Head = newNode;
}
curr.Prev = newNode;
}
public void PrintList() {
Node curr = Head;
while (curr != null) {
Console.Write(" " + curr.Data);
curr = curr.Next;
}
Console.WriteLine();
}
}
class Program {
static void Main(string[] args) {
DoublyLinkedList list = new DoublyLinkedList();
list.Head = new Node(1);
list.Head.Next = new Node(3);
list.Head.Next.Prev = list.Head;
list.Head.Next.Next = new Node(4);
list.Head.Next.Next.Prev = list.Head.Next;
Console.WriteLine("Original Linked List:");
list.PrintList();
Console.WriteLine("Inserting Node with data 2 before node 3:");
list.InsertBefore(3, 2);
list.PrintList();
}
}
Java Implementation
class Node {
int data;
Node next, prev;
Node(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
Node head;
void insertBefore(int key, int newData) {
Node curr = head;
while (curr != null) {
if (curr.data == key) break;
curr = curr.next;
}
if (curr == null) return;
Node newNode = new Node(newData);
newNode.prev = curr.prev;
newNode.next = curr;
if (curr.prev != null) {
curr.prev.next = newNode;
} else {
head = newNode;
}
curr.prev = newNode;
}
void printList() {
Node curr = head;
while (curr != null) {
System.out.print(" " + curr.data);
curr = curr.next;
}
System.out.println();
}
public static void main(String[] args) {
DoublyLinkedList list = new DoublyLinkedList();
list.head = new Node(1);
list.head.next = new Node(3);
list.head.next.prev = list.head;
list.head.next.next = new Node(4);
list.head.next.next.prev = list.head.next;
System.out.println("Original Linked List:");
list.printList();
System.out.println("Inserting Node with data 2 before node 3:");
list.insertBefore(3, 2);
list.printList();
}
}
JavaScript Implementation
class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
}
insertBefore(key, newData) {
let curr = this.head;
while (curr) {
if (curr.data === key) break;
curr = curr.next;
}
if (!curr) return;
const newNode = new Node(newData);
newNode.prev = curr.prev;
newNode.next = curr;
if (curr.prev) {
curr.prev.next = newNode;
} else {
this.head = newNode;
}
curr.prev = newNode;
}
printList() {
let curr = this.head;
while (curr) {
process.stdout.write(` ${curr.data}`);
curr = curr.next;
}
console.log();
}
}
const list = new DoublyLinkedList();
list.head = new Node(1);
list.head.next = new Node(3);
list.head.next.prev = list.head;
list.head.next.next = new Node(4);
list.head.next.next.prev = list.head.next;
console.log("Original Linked List:");
list.printList();
console.log("Inserting Node with data 2 before node 3:");
list.insertBefore(3, 2);
list.printList();
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class DoublyLinkedList:
def __init__(self):
self.head = None
def insert_before(self, key, new_data):
curr = self.head
while curr:
if curr.data == key:
break
curr = curr.next
if not curr:
return
new_node = Node(new_data)
new_node.prev = curr.prev
new_node.next = curr
if curr.prev:
curr.prev.next = new_node
else:
self.head = new_node
curr.prev = new_node
def print_list(self):
curr = self
.head
while curr:
print(curr.data, end=" ")
curr = curr.next
print()
dll = DoublyLinkedList()
dll.head = Node(1)
dll.head.next = Node(3)
dll.head.next.prev = dll.head
dll.head.next.next = Node(4)
dll.head.next.next.prev = dll.head.next
print("Original Linked List:")
dll.print_list()
print("Inserting Node with data 2 before node 3:")
dll.insert_before(3, 2)
dll.print_list()
Output
Original Linked List:
1 3 4
Inserting Node with data 2 before node 3:
1 2 3 4
Time Complexity: O(n), where n is the number of nodes in the doubly linked list
Auxiliary Space: O(1)
Key Takeaways:
- Node Structure: Each language defines a structure or class to represent a node.
- Memory Management:
- C uses
malloc
for dynamic memory allocation. - C++ uses
new
to allocate memory for nodes. - C#, Java, JavaScript, and Python manage memory automatically with garbage collection, but we still need to instantiate objects via
new
in most cases.
- C uses
- Pointer Handling: C and C++ work directly with pointers for node linking, while higher-level languages abstract this away.
- Syntax Differences: Each language has a different way of handling memory allocation, node creation, and syntax for defining classes or structures.
4. Insertion at a Specific Position
To insert a node at a given position (e.g., after the 3rd node), we combine the logic of insertion after a given node and boundary checks:
Steps for Insertion
- Traverse to the Desired Position:
Traverse the list to the node at the positionpos - 1
. - Boundary Checks:
- If
pos
is1
, the operation is equivalent to insertion at the beginning. - If the node is the last node, proceed with insertion at the end.
- If
- Insert the Node:
- Update the
next
pointer of the new node to the node at the positionpos
. - Update the
prev
pointer of the new node to the node at the positionpos - 1
. - Update the surrounding nodes’
next
andprev
pointers accordingly.
- Update the
Implementation In Multiple Programming Languages

Here is the code written in C, C++, C#, Java, JavaScript, and Python, along with a detailed step-by-step explanation for each language.
C Program Implementation
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
// Function to create a new node with the given data
struct Node *createNode(int new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// Function to insert a new node at a given position
struct Node* insertAtPosition(struct Node *head, int pos, int new_data) {
struct Node *new_node = createNode(new_data);
// Insertion at the beginning
if (pos == 1) {
new_node->next = head;
if (head != NULL) {
head->prev = new_node;
}
head = new_node;
return head;
}
struct Node *curr = head;
for (int i = 1; i < pos - 1 && curr != NULL; ++i) {
curr = curr->next;
}
if (curr == NULL) {
printf("Position is out of bounds.\n");
free(new_node);
return head;
}
new_node->prev = curr;
new_node->next = curr->next;
curr->next = new_node;
if (new_node->next != NULL) {
new_node->next->prev = new_node;
}
return head;
}
// Function to print the linked list
void printList(struct Node *head) {
struct Node *curr = head;
while (curr != NULL) {
printf("%d ", curr->data);
curr = curr->next;
}
printf("\n");
}
int main() {
struct Node *head = createNode(1);
head->next = createNode(2);
head->next->prev = head;
head->next->next = createNode(4);
head->next->next->prev = head->next;
printf("Original Linked List: ");
printList(head);
int data = 3;
int pos = 3;
head = insertAtPosition(head, pos, data);
printf("Inserting Node with data 3 at position 3: ");
printList(head);
return 0;
}
Step by Step Explanation
- Define the Node Structure
- A Node contains three elements:
data
: The actual data of the node.next
: A pointer/reference to the next node in the list.prev
: A pointer/reference to the previous node in the list.
- A Node contains three elements:
- Create a New Node Function
- The function
createNode(int new_data)
will create a new node with the provided data and initialize itsnext
andprev
pointers toNULL
(orNone
in Python, JavaScript, Java, C#).
- The function
- Insert a Node at a Given Position
- The function
insertAtPosition(struct Node *head, int pos, int new_data)
inserts a new node at the specified position:- If the position is
1
, the new node is inserted at the head of the list. - For other positions, the list is traversed to the correct location, and the new node is inserted.
- The list is updated to link the previous and next nodes correctly.
- If the position is
- The function
- Print the List
- The
printList()
function will traverse the list and print each node’s data until the end of the list is reached.
- The
C++ Implementation
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int new_data) {
data = new_data;
next = nullptr;
prev = nullptr;
}
};
Node* insertAtPosition(Node* head, int pos, int new_data) {
Node* new_node = new Node(new_data);
if (pos == 1) {
new_node->next = head;
if (head != nullptr) {
head->prev = new_node;
}
head = new_node;
return head;
}
Node* curr = head;
for (int i = 1; i < pos - 1 && curr != nullptr; ++i) {
curr = curr->next;
}
if (curr == nullptr) {
cout << "Position is out of bounds." << endl;
delete new_node;
return head;
}
new_node->prev = curr;
new_node->next = curr->next;
curr->next = new_node;
if (new_node->next != nullptr) {
new_node->next->prev = new_node;
}
return head;
}
void printList(Node* head) {
Node* curr = head;
while (curr != nullptr) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
int main() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->prev = head;
head->next->next = new Node(4);
head->next->next->prev = head->next;
cout << "Original Linked List: ";
printList(head);
int data = 3;
int pos = 3;
head = insertAtPosition(head, pos, data);
cout << "Inserting Node with data 3 at position 3: ";
printList(head);
return 0;
}
C# Implementation
using System;
class Node {
public int Data;
public Node Next;
public Node Prev;
public Node(int new_data) {
Data = new_data;
Next = null;
Prev = null;
}
}
class Program {
static Node InsertAtPosition(Node head, int pos, int new_data) {
Node newNode = new Node(new_data);
if (pos == 1) {
newNode.Next = head;
if (head != null) {
head.Prev = newNode;
}
head = newNode;
return head;
}
Node curr = head;
for (int i = 1; i < pos - 1 && curr != null; ++i) {
curr = curr.Next;
}
if (curr == null) {
Console.WriteLine("Position is out of bounds.");
return head;
}
newNode.Prev = curr;
newNode.Next = curr.Next;
curr.Next = newNode;
if (newNode.Next != null) {
newNode.Next.Prev = newNode;
}
return head;
}
static void PrintList(Node head) {
Node curr = head;
while (curr != null) {
Console.Write(curr.Data + " ");
curr = curr.Next;
}
Console.WriteLine();
}
static void Main() {
Node head = new Node(1);
head.Next = new Node(2);
head.Next.Prev = head;
head.Next.Next = new Node(4);
head.Next.Next.Prev = head.Next;
Console.Write("Original Linked List: ");
PrintList(head);
int data = 3;
int pos = 3;
head = InsertAtPosition(head, pos, data);
Console.Write("Inserting Node with data 3 at position 3: ");
PrintList(head);
}
}
Java Implementation
class Node {
int data;
Node next, prev;
public Node(int new_data) {
data = new_data;
next = null;
prev = null;
}
}
public class DoublyLinkedList {
static Node insertAtPosition(Node head, int pos, int new_data) {
Node newNode = new Node(new_data);
if (pos == 1) {
newNode.next = head;
if (head != null) {
head.prev = newNode;
}
head = newNode;
return head;
}
Node curr = head;
for (int i = 1; i < pos - 1 && curr != null; ++i) {
curr = curr.next;
}
if (curr == null) {
System.out.println("Position is out of bounds.");
return head;
}
newNode.prev = curr;
newNode.next = curr.next;
curr.next = newNode;
if (newNode.next != null) {
newNode.next.prev = newNode;
}
return head;
}
static void printList(Node head) {
Node curr = head;
while (curr != null) {
System.out.print(curr.data + " ");
curr = curr.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
System.out.print("Original Linked List: ");
printList(head);
int data = 3;
int pos = 3;
head = insertAtPosition(head, pos, data);
System.out.print("Inserting Node with data 3 at position 3: ");
printList(head);
}
}
JavaScript Implementation
class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
function insertAtPosition(head, pos, new_data) {
let newNode = new Node(new_data);
if (pos === 1) {
newNode.next = head;
if (head !== null) {
head.prev = newNode;
}
head = newNode;
return head;
}
let curr = head;
for (let i = 1; i < pos - 1 && curr !== null; ++i) {
curr = curr.next;
}
if (curr === null) {
console.log("Position is out of bounds.");
return head;
}
newNode.prev = curr;
newNode.next = curr.next;
curr.next = newNode;
if (newNode.next !== null) {
newNode.next.prev = newNode;
}
return head;
}
function printList(head) {
let curr = head;
while (curr !== null) {
process.stdout.write(curr.data + " ");
curr = curr.next;
}
console.log();
}
let head = new Node(1);
head.next = new Node(2);
head.next.prev = head;
head.next.next = new Node(4);
head.next.next.prev = head.next;
console.log("Original Linked List: ");
printList(head);
let data = 3;
let pos = 3;
head = insertAtPosition(head, pos, data);
console.log("Inserting Node with data 3 at position 3: ");
printList(head);
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
def insert_at_position(head, pos, new_data):
new_node = Node(new_data)
if pos == 1:
new_node.next = head
if head is not None:
head.prev = new_node
head = new_node
return head
curr = head
for _ in range(1, pos - 1):
if curr is None:
print("Position is out of bounds.")
return head
curr = curr.next
new_node.prev = curr
new_node.next = curr.next
curr.next = new_node
if new_node.next is not None:
new_node.next.prev = new_node
return head
def print_list(head):
curr = head
while curr is not None:
print(curr.data, end=" ")
curr = curr.next
print()
head = Node(1)
head.next = Node(2)
head.next.prev = head
head.next.next = Node(4)
head.next.next.prev = head.next
print("Original Linked List: ")
print_list(head)
data = 3
pos = 3
head = insert_at_position(head, pos, data)
print("Inserting Node with data 3 at position 3: ")
print_list(head)
Output
Original Linked List:
1 2 4
Inserting Node with data 3 at position 3:
1 2 3 4
Time Complexity: O(n), where n is the number of nodes in the doubly linked list
Auxiliary Space: O(1)
Summary
In each language:
- A Node class/struct is defined to hold the data, the
next
pointer, and theprev
pointer. - A function to insert a node at a specific position is implemented.
- A function to print the list is provided.
- The node is inserted at the specified position, and the updated list is printed. The output is the same in all languages, showing the insertion of the new node.
5. Insertion at the End
Insertion at the end of a Doubly Linked List is another straightforward operation:
Steps for Insertion
- Create a New Node:
Allocate memory for the new node, initialize it with data, and set itsnext
pointer to NULL. - Check if the List is Empty:
If the list is empty, set the new node as the head. - Traverse to the Last Node:
Traverse the list until the last node is found. - Link the New Node:
Update thenext
pointer of the last node to the new node:curr->next = new_node
. - Update the New Node’s Previous Pointer:
Set theprev
pointer of the new node to the last node:new_node->prev = curr
.
Example
Given the list {10 <-> 20 <-> 30}
and inserting 40
at the end, the result will be {10 <-> 20 <-> 30 <-> 40}
.
Implementation In Multiple Programming Languages

Here is the code written in C, C++, C#, Java, JavaScript, and Python, along with a detailed step-by-step explanation for each language.
C Program Implementation
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next;
struct Node *prev;
};
// Function to create a new node with the given data
struct Node *createNode(int new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
new_node->prev = NULL;
return new_node;
}
// Function to insert a new node at the end of the doubly linked list
struct Node* insertEnd(struct Node *head, int new_data) {
struct Node *new_node = createNode(new_data);
if (head == NULL) {
head = new_node;
} else {
struct Node *curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new_node;
new_node->prev = curr;
}
return head;
}
// Function to print the linked list
void printList(struct Node *head) {
struct Node *curr = head;
while (curr != NULL) {
printf("%d ", curr->data);
curr = curr->next;
}
printf("\n");
}
int main() {
struct Node *head = createNode(1);
head->next = createNode(2);
head->next->prev = head;
head->next->next = createNode(3);
head->next->next->prev = head->next;
printf("Original Linked List: ");
printList(head);
printf("Inserting Node with data 4 at the end: ");
head = insertEnd(head, 4);
printList(head);
return 0;
}
Step by Step Explanation
- Define the Node Structure/Class:
- A Node class/struct is created to represent each element in the doubly linked list. It contains:
data
: The value stored in the node.next
: A pointer/reference to the next node.prev
: A pointer/reference to the previous node.
- A Node class/struct is created to represent each element in the doubly linked list. It contains:
- Create a Node Function:
- The function
createNode(int new_data)
initializes a new node with the given data and sets bothnext
andprev
pointers toNULL
.
- The function
- Insert at the End Function:
- The function
insertEnd()
inserts a new node at the end of the doubly linked list:- If the list is empty (
head == NULL
), the new node becomes the head. - If the list is not empty, the function traverses to the last node and attaches the new node at the end.
- The
prev
pointer of the new node is set to the last node, and thenext
pointer of the last node is set to the new node.
- If the list is empty (
- The function
- Print the List:
- The
printList()
function traverses the list from the head and prints each node’sdata
.
- The
C++ Implementation
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int new_data) {
data = new_data;
next = nullptr;
prev = nullptr;
}
};
Node* insertEnd(Node* head, int new_data) {
Node* new_node = new Node(new_data);
if (head == nullptr) {
head = new_node;
} else {
Node* curr = head;
while (curr->next != nullptr) {
curr = curr->next;
}
curr->next = new_node;
new_node->prev = curr;
}
return head;
}
void printList(Node* head) {
Node* curr = head;
while (curr != nullptr) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
int main() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->prev = head;
head->next->next = new Node(3);
head->next->next->prev = head->next;
cout << "Original Linked List: ";
printList(head);
cout << "Inserting Node with data 4 at the end: ";
head = insertEnd(head, 4);
printList(head);
return 0;
}
C# Implementation
using System;
class Node {
public int Data;
public Node Next;
public Node Prev;
public Node(int new_data) {
Data = new_data;
Next = null;
Prev = null;
}
}
class Program {
static Node InsertEnd(Node head, int new_data) {
Node newNode = new Node(new_data);
if (head == null) {
head = newNode;
} else {
Node curr = head;
while (curr.Next != null) {
curr = curr.Next;
}
curr.Next = newNode;
newNode.Prev = curr;
}
return head;
}
static void PrintList(Node head) {
Node curr = head;
while (curr != null) {
Console.Write(curr.Data + " ");
curr = curr.Next;
}
Console.WriteLine();
}
static void Main() {
Node head = new Node(1);
head.Next = new Node(2);
head.Next.Prev = head;
head.Next.Next = new Node(3);
head.Next.Next.Prev = head.Next;
Console.Write("Original Linked List: ");
PrintList(head);
Console.Write("Inserting Node with data 4 at the end: ");
head = InsertEnd(head, 4);
PrintList(head);
}
}
Java Implementation
class Node {
int data;
Node next, prev;
public Node(int new_data) {
data = new_data;
next = null;
prev = null;
}
}
public class DoublyLinkedList {
static Node insertEnd(Node head, int new_data) {
Node newNode = new Node(new_data);
if (head == null) {
head = newNode;
} else {
Node curr = head;
while (curr.next != null) {
curr = curr.next;
}
curr.next = newNode;
newNode.prev = curr;
}
return head;
}
static void printList(Node head) {
Node curr = head;
while (curr != null) {
System.out.print(curr.data + " ");
curr = curr.next;
}
System.out.println();
}
public static void main(String[] args) {
Node head = new Node(1);
head.next = new Node(2);
head.next.prev = head;
head.next.next = new Node(3);
head.next.next.prev = head.next;
System.out.print("Original Linked List: ");
printList(head);
System.out.print("Inserting Node with data 4 at the end: ");
head = insertEnd(head, 4);
printList(head);
}
}
JavaScript Implementation
class Node {
constructor(data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
function insertEnd(head, new_data) {
let newNode = new Node(new_data);
if (head === null) {
head = newNode;
} else {
let curr = head;
while (curr.next !== null) {
curr = curr.next;
}
curr.next = newNode;
newNode.prev = curr;
}
return head;
}
function printList(head) {
let curr = head;
while (curr !== null) {
process.stdout.write(curr.data + " ");
curr = curr.next;
}
console.log();
}
let head = new Node(1);
head.next = new Node(2);
head.next.prev = head;
head.next.next = new Node(3);
head.next.next.prev = head.next;
console.log("Original Linked List: ");
printList(head);
let data = 4;
head = insertEnd(head, data);
console.log("Inserting Node with data 4 at the end: ");
printList(head);
Python Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
def insert_end(head, new_data):
new_node = Node(new_data)
if head is None:
head = new_node
else:
curr = head
while curr.next is not None:
curr = curr.next
curr.next = new_node
new_node.prev = curr
return head
def print_list(head):
curr = head
while curr is not None:
print(curr.data, end=" ")
curr = curr.next
print()
head = Node(1)
head.next = Node(2)
head.next.prev = head
head.next.next = Node(3)
head.next.next.prev = head.next
print("Original Linked List: ")
print_list(head)
data = 4
head = insert_end(head, data)
print("Inserting Node with data 4 at the end: ")
print_list(head)
Output
Original Linked List:
1 2 3
Inserting Node with data 4 at the end:
1 2 3 4
Time Complexity: O(1)
Auxiliary Space: O(1)
Summary
In all languages:
- A
Node
class/struct is defined to store the data, next pointer, and previous pointer. - A function
insertEnd()
is created to insert a new node at the end of the list. - A function
printList()
is used to print the list. - The new node with the value 4 is inserted at the end of the list.
- The updated list is printed in each case.
Differences Between Types of Insertions in a Doubly Linked List
The table below outlines the key distinctions between the five types of insertions in a Doubly Linked List, including steps, affected nodes, and typical use cases.
Aspect | Insertion at Beginning | Insertion After a Given Node | Insertion Before a Given Node | Insertion at a Specific Position | Insertion at the End |
---|---|---|---|---|---|
Insertion Location | Inserts the new node as the first node of the list. | Inserts the new node immediately after a specified node. | Inserts the new node immediately before a specified node. | Inserts the new node at a specified position (1-based index) within the list. | Inserts the new node as the last node of the list. |
Affected Nodes | Updates the current head’s prev pointer (if the list is not empty). | Updates the next pointer of the given node and the prev pointer of the next node (if it exists). | Updates the prev pointer of the given node and the next pointer of the previous node (if it exists). | Updates both the prev and next pointers of nodes at positions pos - 1 and pos . | Updates the next pointer of the current last node and the prev pointer of the new node. |
Steps to Perform | 1. Create the new node with prev = NULL .2. Update the new node’s next to the current head.3. Update the current head’s prev pointer. | 1. Locate the target node. 2. Create the new node with prev pointing to the target node.3. Update surrounding pointers. | 1. Locate the target node. 2. Create the new node with next pointing to the target node.3. Update surrounding pointers. | 1. Locate the position pos - 1 .2. Create the new node and adjust prev and next pointers of surrounding nodes based on the position. | 1. Traverse the list to find the last node. 2. Create the new node with next = NULL .3. Update next and prev pointers as required. |
Boundary Conditions | If the list is empty, the new node becomes the head. | Cannot insert if the target node does not exist in the list. | Cannot insert if the target node does not exist in the list. | If the position is 1, it is equivalent to insertion at the beginning. If the position exceeds the length, it is equivalent to insertion at the end. | If the list is empty, the new node becomes the head. |
Pointer Adjustments Required | – Update head to the new node.– Update next of the new node.– Update prev of the old head (if not empty). | – Update next of the target node.– Update prev of the new node.– Update prev of the target’s next node (if it exists). | – Update prev of the target node.– Update next of the previous node.– Update next and prev of the new node. | – Update prev of the new node to the node at pos - 1 .– Update next and prev pointers of nodes at positions pos - 1 and pos . | – Update next of the last node to the new node.– Update prev of the new node to the last node. |
Ease of Implementation | Simple, as only the head pointer and its neighbors are affected. | Moderate, as it requires traversing to the target node and updating its neighbors. | Moderate, as it requires traversing to the target node and updating its neighbors. | Slightly complex, as it involves boundary checks and updating multiple nodes’ pointers. | Simple, as only the last node and the new node are involved. |
Typical Use Cases | – Adding elements to the front of the list. – Implementing stacks with LIFO order. | – Adding an element in a middle position after a specific node. – Useful for ordered insertions. | – Adding an element in a middle position before a specific node. – Useful for ordered insertions. | – Placing an element at an exact position (e.g., in sorted or unsorted lists). | – Appending elements to the list. – Maintaining FIFO order in queues. |
Example (Initial: {10 <-> 20 <-> 30}) | Insert 5 at the beginning:Result: {5 <-> 10 <-> 20 <-> 30} | Insert 25 after 20 :Result: {10 <-> 20 <-> 25 <-> 30} | Insert 15 before 20 :Result: {10 <-> 15 <-> 20 <-> 30} | Insert 25 at position 3:Result: {10 <-> 20 <-> 25 <-> 30} | Insert 40 at the end:Result: {10 <-> 20 <-> 30 <-> 40} |
Each insertion type in a Doubly Linked List serves a distinct purpose. By understanding their differences and use cases, developers can optimize their data manipulation tasks, ensuring that their operations are both efficient and tailored to the specific requirements of their applications.
Conclusion
Insertion in a Doubly Linked List is a fundamental operation that highlights the versatility of this data structure. The key difference between Singly Linked Lists and Doubly Linked Lists lies in the additional prev
pointer, which allows for more efficient operations, particularly in reverse traversal and deletion. By mastering these insertion techniques, one can harness the full potential of Doubly Linked Lists in programming applications.
Related Articles
- Insertion in Doubly Linked List with Implementation: A Detailed Exploration
- Inserting a Node at the Beginning of a Doubly Linked List: A Detailed Exploration
- Inserting a Node After a Given Node in a Doubly Linked List: A Detailed Exploration
- Inserting a Node Before a Given Node in a Doubly Linked List: A Detailed Exploration
- Inserting a Node at a Specific Position in a Doubly Linked List: A Detailed Exploration
- Inserting a New Node at the End of a Doubly Linked List: A Detailed Exploration
Read More Articles
- Data Structure (DS) Array:
- Why the Analysis of Algorithms is Important?
- Worst, Average, and Best Case Analysis of Algorithms: A Comprehensive Guide
- Understanding Pointers in C Programming: A Comprehensive Guide
- Understanding Arrays in Data Structures: A Comprehensive Exploration
- Memory Allocation of an Array: An In-Depth Comprehensive Exploration
- Understanding Basic Operations in Arrays: A Comprehensive Guide
- Understanding 2D Arrays in Programming: A Comprehensive Guide
- Mapping a 2D Array to a 1D Array: A Comprehensive Exploration
- Data Structure Linked List:
- Understanding Linked Lists in Data Structures: A Comprehensive Exploration
- Types of Linked List: Detailed Exploration, Representations, and Implementations
- Understanding Singly Linked Lists: A Detailed Exploration
- Understanding Doubly Linked List: A Comprehensive Guide
- Operations of Doubly Linked List with Implementation: A Detailed Exploration
- Insertion in Doubly Linked List with Implementation: A Detailed Exploration
- Inserting a Node at the Beginning of a Doubly Linked List: A Detailed Exploration
- Inserting a Node After a Given Node in a Doubly Linked List: A Detailed Exploration
- Inserting a Node Before a Given Node in a Doubly Linked List: A Detailed Exploration
- Inserting a Node at a Specific Position in a Doubly Linked List: A Detailed Exploration
- Inserting a New Node at the End of a Doubly Linked List: A Detailed Exploration
- Deletion in a Doubly Linked List with Implementation: A Comprehensive Guide
- Deletion at the Beginning in a Doubly Linked List: A Detailed Exploration
- Deletion after a given node in Doubly Linked List: A Comprehensive Guide
- Deleting a Node Before a Given Node in a Doubly Linked List: A Detailed Exploration
- Deletion at a Specific Position in a Doubly Linked List: A Detailed Exploration
- Deletion at the End in Doubly Linked List: A Comprehensive Exploration
- Introduction to Circular Linked Lists: A Comprehensive Guide
- Understanding Circular Singly Linked Lists: A Comprehensive Guide
- Circular Doubly Linked List: A Comprehensive Guide
- Insertion in Circular Singly Linked List: A Comprehensive Guide
- Insertion in an Empty Circular Linked List: A Detailed Exploration
- Insertion at the Beginning in Circular Linked List: A Detailed Exploration
- Insertion at the End of a Circular Linked List: A Comprehensive Guide
- Insertion at a Specific Position in a Circular Linked List: A Detailed Exploration
- Deletion from a Circular Linked List: A Comprehensive Guide
- Deletion from the Beginning of a Circular Linked List: A Detailed Exploration
- Deletion at Specific Position in Circular Linked List: A Detailed Exploration
- Deletion at the End of a Circular Linked List: A Comprehensive Guide
- Searching in a Circular Linked List: A Comprehensive Exploration
Frequently Asked Questions (FAQs)
What is a Doubly Linked List (DLL)?
A Doubly Linked List (DLL) is a type of data structure where each node contains three components:
- Data Field: Stores the actual value of the node.
- Next Pointer: Points to the next node in the list.
- Previous Pointer (Prev): Points to the previous node in the list.
The bidirectional nature of DLLs enables efficient traversal in both directions, making them more versatile than Singly Linked Lists (SLL). This capability is particularly useful in scenarios requiring quick insertion, deletion, or bidirectional traversal, such as navigation systems or undo operations in text editors.
What are the different types of insertion operations in a Doubly Linked List?
Insertion in a Doubly Linked List can be performed in five ways:
- Insertion at the Beginning: Adds a new node at the start of the list.
- Insertion After a Given Node: Adds a new node immediately after a specified node.
- Insertion Before a Given Node: Adds a new node immediately before a specified node.
- Insertion at a Specific Position: Inserts the new node at a particular index within the list.
- Insertion at the End: Appends a new node as the last node in the list.
Each type of insertion modifies specific pointers (next
and prev
) in the nodes to maintain the structure of the DLL.
How does insertion at the beginning of a DLL work?
To insert a new node at the start of a DLL, follow these steps:
- Create a New Node: Allocate memory and initialize it with the required data. Set its
prev
pointer to NULL since it will be the first node. - Link to the Current Head: Update the
next
pointer of the new node to point to the current head of the list. - Update the Current Head’s Prev Pointer: If the list is not empty, update the
prev
pointer of the current head to point to the new node. - Set the New Node as Head: Update the head pointer of the list to the new node.
This operation is efficient because only the first node and the head pointer are affected.
What steps are required to insert a node after a specific node?
Insertion after a given node involves updating the surrounding pointers of the new and adjacent nodes. Here’s how:
- Locate the Target Node: Traverse the list to find the node after which the new node will be inserted.
- Create a New Node: Allocate memory and initialize it. Set the
prev
pointer of the new node to the target node. - Link the New Node to the Next Node: Update the
next
pointer of the new node to point to the target node’s next node. - Update Target Node’s Next Pointer: Set the
next
pointer of the target node to the new node. - Update the Next Node’s Prev Pointer (if Applicable): If the new node is not the last node, update the
prev
pointer of the target’s next node to point back to the new node.
This operation is particularly useful in ordered or unsorted lists for inserting new elements in the middle.
What are the differences between insertion before and after a node?
Aspect | Insertion After a Node | Insertion Before a Node |
---|---|---|
Location | Inserts a new node after the specified node. | Inserts a new node before the specified node. |
Updated Pointers | – next of target node– prev of new node | – prev of target node– next of previous node |
Use Case | Adding a new element to follow an existing node. | Adding a new element to precede an existing node. |
Example | Insert 25 after 20 in {10 <-> 20 <-> 30} : {10 <-> 20 <-> 25 <-> 30} | Insert 15 before 20 in {10 <-> 20 <-> 30} : {10 <-> 15 <-> 20 <-> 30} |
Both types of insertion require proper handling of the surrounding next
and prev
pointers to maintain the list’s structure.
How can a node be inserted at a specific position in the list?
To insert a node at a given position (1-based index):
- Locate Position: Traverse the list to the node at position
pos - 1
. - Boundary Checks:
- If
pos = 1
, perform an insertion at the beginning. - If
pos
exceeds the length of the list, perform an insertion at the end.
- If
- Insert Node:
- Update the
next
pointer of the new node to point to the node at positionpos
. - Update the
prev
pointer of the new node to point to the node at positionpos - 1
. - Adjust the surrounding pointers (
next
andprev
) of nodes atpos - 1
andpos
.
- Update the
This operation allows the precise placement of elements within the list.
What happens during insertion at the end of a Doubly Linked List?
Insertion at the end involves appending a new node as the last node in the list:
- Create a New Node: Allocate memory, initialize it with data, and set its
next
pointer to NULL. - Handle Empty List: If the list is empty, set the new node as the head.
- Traverse to the Last Node: Iterate through the list to locate the last node.
- Update Last Node’s Next Pointer: Set the
next
pointer of the last node to the new node. - Update New Node’s Prev Pointer: Set the
prev
pointer of the new node to the last node.
This is a straightforward operation as it only affects the last node and the new node.
What are the common boundary conditions to check during insertion?
When inserting nodes in a Doubly Linked List, the following boundary conditions must be considered:
- Empty List:
- If the list is empty, the new node becomes the head.
- Position Out of Bounds:
- If inserting at position
1
, perform insertion at the beginning. - If inserting beyond the last node, perform insertion at the end.
- If inserting at position
- Single Node List:
- If the list contains only one node, ensure that both
next
andprev
pointers are updated correctly.
- If the list contains only one node, ensure that both
Proper handling of these conditions prevents segmentation faults or invalid pointer dereferencing.
What are the time complexities for different types of insertion?
Insertion Type | Time Complexity |
---|---|
Insertion at the Beginning | O(1): Only the head pointer and its neighbors are updated. |
Insertion After a Node | O(n): May require traversal to locate the target node. |
Insertion Before a Node | O(n): Similar to insertion after a node. |
Insertion at a Position | O(n): Traversal is required to locate the target position. |
Insertion at the End | O(n): Traversal is required to locate the last node. |
For all types, the pointer update operations are O(1), but the traversal to find the target node increases the complexity.
Why choose Doubly Linked Lists over Singly Linked Lists for insertions?
Doubly Linked Lists (DLLs) offer advantages over Singly Linked Lists (SLLs) due to their bidirectional pointers. Key benefits include:
- Efficient Backward Traversal: The
prev
pointer allows moving in reverse, unlike SLLs, which can only traverse forward. - Simpler Insertions and Deletions: In DLLs, both
next
andprev
pointers are available, eliminating the need to traverse the list for previous nodes during insertion or deletion. - Enhanced Flexibility: DLLs are ideal for applications requiring frequent updates at both ends (e.g., deque operations) or in the middle.
While DLLs consume more memory due to the additional pointer, their efficiency in dynamic operations makes them a preferred choice in many applications.