Implementation of Deque using doubly linked list

Last Updated : 19 Sep, 2025

Doubly Linked List implementation of deque allows constant-time insertion and deletion at both ends. We only need to maintain pointers or references to both the ends, front and rear.

deque-using-ll

Operations on Deque

The following four basic operations are typically performed on a deque:

  • insertFront(): Adds an item at the front.
  • insertRear(): Adds an item at the rear.
  • deleteFront(): Removes the front item.
  • deleteRear(): Removes the rear item.

Additionally, the following operations are also supported:

  • getFront(): Retrieves the front item
  • getRear(): Retrieves the last item
  • isEmpty(): Checks if the deque is empty.
  • size(): Returns the number of elements in the deque.
  • erase(): Removes all elements

All operations on a deque,take O(1) time and O(1) extra space. Only the erase() operation takes O(n) time, since it removes all elements from the deque.

Try It Yourself
redirect icon

Doubly Linked List Representation of Deque:

  1. Define a Doubly Linked List Node structure containing, data, prev and next
  2. Declare two pointers, front and rear, of type Node and initialize both as NULL to represent an empty deque.
C++
class Node {
public:

    int data;
    Node* prev;
    Node* next;
    Node(int data) { 
        this->data = data; 
        prev = next = nullptr; 
    }
};

class myDeque {
    Node* front;
    Node* rear;
public:

    myDeque() { 
        front = rear = nullptr; 
    }
}
Java
class Node {
    int data;
    Node prev;
    Node next;
    Node(int data) { 
        this.data = data; 
        this.prev = this.next = null; 
    }
}

class myDeque {
    Node front;
    Node rear;
    MyDeque() { 
        front = rear = null; 
    }
}
Python
class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

class myDeque:
    def __init__(self):
        self.front = self.rear = None
C#
public class Node {
    public int data { get; set; }
    public Node prev { get; set; }
    public Node next { get; set; }
    public Node(int data) {
        this.data = data;
        this.prev = this.next = null;
    }
}

public class myDeque {
    public Node front { get; set; }
    public Node rear { get; set; }
    public MyDeque() {
        this.front = this.rear = null;
    }
}
JavaScript
class Node {
    constructor(data) {
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

class myDeque {
    constructor() {
        this.front = this.rear = null;
    }
}

Insertion at Front :

  1. Allocate a new node (newNode) for the doubly linked list.
  2. Check if the deque is empty:
    => If front == NULL, set both front and rear to newNode.
  3. If the deque is not empty:
    => Set newNode->next = front (link new node to current front).
    => Set front->prev = newNode (link current front back to new node).
    => Update front = newNode (move front pointer to new node).
C++
void insertFront(int data) {
    Node* newNode = new Node(data);
        
    // empty deque
    if (!front) { 
        front = rear = newNode;
    } else {
        newNode->next = front;
        front->prev = newNode;
        front = newNode;
    }
}
Java
void insertFront(int data) {
    Node newNode = new Node(data);
        
    // empty deque
    if (front == null) { 
        front = rear = newNode;
    } else {
        newNode.next = front;
        front.prev = newNode;
        front = newNode;
    }
}
Python
def insertFront(self, data):
    newNode = Node(data)
        
    # empty deque
    if self.front is None: 
        self.front = self.rear = newNode
    else:
        newNode.next = self.front
        self.front.prev = newNode
        self.front = newNode
C#
public void insertFront(int data) {
    Node newNode = new Node(data);
        
    // empty deque
    if (front == null) { 
        front = rear = newNode;
    } else {
        newNode.next = front;
        front.prev = newNode;
        front = newNode;
    }
}
JavaScript
function insertFront(data) {
    let newNode = new Node(data);
    
    // empty deque
    if (!this.front) { 
        this.front = this.rear = newNode;
    } else {
        newNode.next = this.front;
        this.front.prev = newNode;
        this.front = newNode;
    }
}

Insertion at Rear :

  1. Allocate a new node (newNode) for the doubly linked list.
  2. Check if the deque is empty:
    => If rear == NULL, set both front and rear to newNode.
  3. If the deque is not empty:
    => Set newNode->prev = rear (link new node back to current rear).
    => Set rear->next = newNode (link current rear forward to new node).
    => Update rear = newNode (move rear pointer to new node).
C++
void insertRear(int data) {
    Node *newNode = new Node(data);

    // empty deque
    if (rear == nullptr) {
        front = rear = newNode;
    }
    else {
        newNode->prev = rear;
        rear->next = newNode;
        rear = newNode;
    }
}
Java
void insertRear(int data) {
    Node newNode = new Node(data);

    // empty deque
    if (rear == null) {
        front = rear = newNode;
    }
    else {
        newNode.prev = rear;
        rear.next = newNode;
        rear = newNode;
    }
}
Python
def insertRear(self, data):

    # memory allocation check
    newNode = Node(data)
    
    # empty deque
    if self.rear is None:
        self.front = self.rear = newNode
    else:
        newNode.prev = self.rear
        self.rear.next = newNode
        self.rear = newNode
C#
public void insertRear(int data) {
    Node newNode = new Node(data);
    
    // empty deque
    if (rear == null) {
        front = rear = newNode;
    }
    else {
        newNode.prev = rear;
        rear.next = newNode;
        rear = newNode;
    }
}
JavaScript
function insertRear(data) {
    let newNode = new Node(data);

    // empty deque
    if (this.rear === null) {
        this.front = this.rear = newNode;
    }
    else {
        newNode.prev = this.rear;
        this.rear.next = newNode;
        this.rear = newNode;
    }
}

Deletion from Front end :

  1. Check if the deque is empty:
    => If front == NULL, print "Underflow" and exit.
  2. Store the current front node:
    => temp = front
  3. Move the front pointer to the next node:
    => front = front->next
  4. Update rear or front pointers:
    => If front == NULL, the deque is now empty, so set rear = NULL
    => Else, set front->prev = NULL to detach the old front node
  5. Deallocate memory of the removed node:
    => delete temp (or equivalent in your language)
C++
void deleteFront() {
    
    // empty deque
    if (front == nullptr) { 
        cout << "Underflow\n";
        return;
    }
    
    Node* temp = front;
    front = front->next;
    
    if (front) front->prev = nullptr;
    else rear = nullptr;
    delete temp;
    
    size--;
}
Java
void deleteFront() {
    
    // empty deque
    if (front == null) { 
        System.out.println("Underflow");
        return;
    }
    
    Node temp = front;
    front = front.next;
    
    if (front == null)
        rear = null;
    else
        front.prev = null;
}
Python
def deleteFront(self):
    
     # empty deque
    if self.front is None: 
        print("Underflow")
        return

    temp = self.front
    self.front = self.front.next

    # deque becomes empty
    if self.front is None: 
        self.rear = None
    else:
        self.front.prev = None
    del temp
C#
public void deleteFront() {
    
    // empty deque
    if (front == null) { 
        Console.WriteLine("Underflow");
        return;
    }
    
    Node temp = front;
    front = front.next;
    if (front == null)
        rear = null;
    else
        front.prev = null;

    // dereference for garbage collection
    temp = null; 
}
JavaScript
function deleteFront() {
    
    // empty deque
    if (!this.front) { 
        console.log("Underflow");
        return;
    }
    
    let temp = this.front;
    this.front = this.front.next;
    
    // deque becomes empty
    if (!this.front)
        this.rear = null;
    else
        this.front.prev = null;

    // dereference for garbage collection
    temp = null; 
}

Deletion from Rear end :

  1. Check if the deque is empty:
    => front == NULL (or rear == NULL), print "Underflow" and exit.
  2. Store the current rear node:
    => temp = rear
  3. Move the rear pointer to the previous node:
    => rear = rear->prev
  4. Update front or rear pointers:
    => If rear == NULL, the deque is now empty, so set front = NULL
    => Else, set rear->next = NULL to detach the old rear node
  5. Deallocate memory of the removed node:
    => delete temp (or equivalent in your language)
C++
void deleteRear() {
    if (rear == nullptr) {
        cout << "Underflow\n";
        return;
    }
    Node* temp = rear;
    rear = rear->prev;

    if (rear == nullptr) 
        front = nullptr;
    else
        rear->next = nullptr;

    delete temp;
    size--;
}
Java
void deleteRear() {
    if (rear == null) { 
        System.out.println("Underflow");
        return;
    }
    Node temp = rear;
    rear = rear.prev;

    if (rear == null) 
        front = null;
    else
        rear.next = null;
}
Python
def deleteRear(self):
    if self.rear is None: 
        print("Underflow")
        return
    temp = self.rear
    self.rear = self.rear.prev

    if self.rear is None:  
        self.front = None
    else:
        self.rear.next = None

    del temp
C#
public void deleteRear() {
    if (rear == null) { 
        Console.WriteLine("Underflow");
        return;
    }
    Node temp = rear;
    rear = rear.prev;

    if (rear == null) 
        front = null;
    else
        rear.next = null;

    temp = null; 
}
JavaScript
function deleteRear() {
    if (!this.rear) {
        console.log("Underflow");
        return;
    }
    let temp = this.rear;
    this.rear = this.rear.prev;

    if (!this.rear) 
        this.front = null;
    else
        this.rear.next = null;

    temp = null;
}

Complete Implementation:

C++
#include <iostream>
using namespace std;

// Node class for doubly linked list
class Node {
public:
    int data;
    Node *prev, *next;

    Node(int data) { 
        this->data = data; 
        prev = nullptr; 
        next = nullptr; 
    }
};

// Deque implementation using doubly linked list
class myDeque {
    Node *front, *rear;
    int size;

public:
    myDeque() { 
        front = nullptr; 
        rear = nullptr; 
        size = 0; 
    }

    bool isEmpty() { return front == nullptr; }
    int getSize() { return size; }

    // Insert at front
    void insertFront(int data) {
        Node* newNode = new Node(data);
       
        if (isEmpty()) front = rear = newNode;
        else {
            newNode->next = front;
            front->prev = newNode;
            front = newNode;
        }
       
        size++;
    }

    // Insert at rear
    void insertRear(int data) {
        Node* newNode = new Node(data);
        
        if (isEmpty()) front = rear = newNode;
        else {
            newNode->prev = rear;
            rear->next = newNode;
            rear = newNode;
        }
        size++;
    }

    // Delete from front
    void deleteFront() {
        if (isEmpty()) cout << "UnderFlow\n";
        else {
            front = front->next;
            if (front) front->prev = nullptr;
            else rear = nullptr;
            size--;
        }
    }

    // Delete from rear
    void deleteRear() {
        if (isEmpty()) cout << "UnderFlow\n";
        else {
            rear = rear->prev;
            if (rear) rear->next = nullptr;
            else front = nullptr;
         
            size--;
        }
    }

    // Get front element
    int getFront() { return isEmpty() ? -1 : front->data; }

    // Get rear element
    int getRear() { return isEmpty() ? -1 : rear->data; }

    // Clear the deque
    void erase() {
        while (!isEmpty()) deleteFront();
    }
};

int main() {
    myDeque dq;

    dq.insertRear(5);
    dq.insertRear(10);
    cout << "Rear: " << dq.getRear() << endl;

    dq.deleteRear();
    cout << "New Rear: " << dq.getRear() << endl;

    dq.insertFront(15);
    cout << "Front: " << dq.getFront() << endl;
    cout << "Size: " << dq.getSize() << endl;

    dq.deleteFront();
    cout << "New Front: " << dq.getFront() << endl;

    return 0;
}
C
#include <stdio.h>
#include <stdlib.h>

// Node for doubly linked list
struct Node {
    int data;
    struct Node *prev, *next;
};

// Deque structure
struct myDeque {
    struct Node *front, *rear;
    int size;
};

// Create a new deque
struct myDeque* createMyDeque() {
    struct myDeque* dq = (struct myDeque*)malloc(sizeof(struct myDeque));
    dq->front = dq->rear = NULL;
    dq->size = 0;
    return dq;
}

// Check if deque is empty
int isEmpty(struct myDeque* dq) { return dq->front == NULL; }

// Get current size
int getSize(struct myDeque* dq) { return dq->size; }

// Insert at front
void insertFront(struct myDeque* dq, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->prev = NULL;
    newNode->next = dq->front;

    if (isEmpty(dq)) dq->front = dq->rear = newNode;
    else {
        dq->front->prev = newNode;
        dq->front = newNode;
    }
    dq->size++;
}

// Insert at rear
void insertRear(struct myDeque* dq, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;

    if (isEmpty(dq)) {
        newNode->prev = NULL;
        dq->front = dq->rear = newNode;
    } else {
        newNode->prev = dq->rear;
        dq->rear->next = newNode;
        dq->rear = newNode;
    }
    dq->size++;
}

// Delete from front
void deleteFront(struct myDeque* dq) {
    if (isEmpty(dq)) {
        printf("UnderFlow\n");
        return;
    }
    dq->front = dq->front->next;
    if (dq->front) dq->front->prev = NULL;
    else dq->rear = NULL;
    dq->size--;
}

// Delete from rear
void deleteRear(struct myDeque* dq) {
    if (isEmpty(dq)) {
        printf("UnderFlow\n");
        return;
    }
    dq->rear = dq->rear->prev;
    if (dq->rear) dq->rear->next = NULL;
    else dq->front = NULL;
    dq->size--;
}

// Get front element
int getFront(struct myDeque* dq) { return isEmpty(dq) ? -1 : dq->front->data; }

// Get rear element
int getRear(struct myDeque* dq) { return isEmpty(dq) ? -1 : dq->rear->data; }

// Clear deque
void erase(struct myDeque* dq) {
    while (!isEmpty(dq)) deleteFront(dq);
}

int main() {
    struct myDeque* dq = createMyDeque();

    insertRear(dq, 5);
    insertRear(dq, 10);
    printf("Rear: %d\n", getRear(dq));

    deleteRear(dq);
    printf("New Rear: %d\n", getRear(dq));

    insertFront(dq, 15);
    printf("Front: %d\n", getFront(dq));
    printf("Size: %d\n", getSize(dq));

    deleteFront(dq);
    printf("New Front: %d\n", getFront(dq));

    return 0;
}
Java
class Node {
    int data;
    Node prev, next;

    Node(int data) {
        this.data = data;
        prev = null;
        next = null;
    }
}

// Deque implementation using doubly linked list
class myDeque {
    Node front, rear;
    int size;

    myDeque() {
        front = null;
        rear = null;
        size = 0;
    }

    boolean isEmpty() { return front == null; }
    int getSize() { return size; }

    // Insert at front
    void insertFront(int data) {
        Node newNode = new Node(data);
        if (isEmpty()) front = rear = newNode;
        else {
            newNode.next = front;
            front.prev = newNode;
            front = newNode;
        }
        size++;
    }

    // Insert at rear
    void insertRear(int data) {
        Node newNode = new Node(data);
        if (isEmpty()) front = rear = newNode;
        else {
            newNode.prev = rear;
            rear.next = newNode;
            rear = newNode;
        }
        size++;
    }

    // Delete from front
    void deleteFront() {
        if (isEmpty()) System.out.println("UnderFlow");
        else {
            front = front.next;
            if (front != null) front.prev = null;
            else rear = null;
            size--;
        }
    }

    // Delete from rear
    void deleteRear() {
        if (isEmpty()) System.out.println("UnderFlow");
        else {
            rear = rear.prev;
            if (rear != null) rear.next = null;
            else front = null;
            size--;
        }
    }

    // Get front element
    int getFront() { return isEmpty() ? -1 : front.data; }

    // Get rear element
    int getRear() { return isEmpty() ? -1 : rear.data; }

    // Clear deque
    void erase() {
        while (!isEmpty()) deleteFront();
    }
}

// Driver code
public class Main {
    public static void main(String[] args) {
        myDeque dq = new myDeque();

        dq.insertRear(5);
        dq.insertRear(10);
        System.out.println("Rear: " + dq.getRear());

        dq.deleteRear();
        System.out.println("New Rear: " + dq.getRear());

        dq.insertFront(15);
        System.out.println("Front: " + dq.getFront());
        System.out.println("Size: " + dq.getSize());

        dq.deleteFront();
        System.out.println("New Front: " + dq.getFront());
    }
}
Python
class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None
        self.next = None

# Deque implementation using doubly linked list
class myDeque:
    def __init__(self):
        self.front = None
        self.rear = None
        self.size = 0

    def isEmpty(self):
        return self.front is None

    def getSize(self):
        return self.size

    # Insert at front
    def insertFront(self, data):
        newNode = Node(data)
        if self.isEmpty():
            self.front = self.rear = newNode
        else:
            newNode.next = self.front
            self.front.prev = newNode
            self.front = newNode
        self.size += 1

    # Insert at rear
    def insertRear(self, data):
        newNode = Node(data)
        if self.isEmpty():
            self.front = self.rear = newNode
        else:
            newNode.prev = self.rear
            self.rear.next = newNode
            self.rear = newNode
        self.size += 1

    # Delete from front
    def deleteFront(self):
        if self.isEmpty():
            print("UnderFlow")
        else:
            self.front = self.front.next
            if self.front:
                self.front.prev = None
            else:
                self.rear = None
            self.size -= 1

    # Delete from rear
    def deleteRear(self):
        if self.isEmpty():
            print("UnderFlow")
        else:
            self.rear = self.rear.prev
            if self.rear:
                self.rear.next = None
            else:
                self.front = None
            self.size -= 1

    # Get front element
    def getFront(self):
        return -1 if self.isEmpty() else self.front.data

    # Get rear element
    def getRear(self):
        return -1 if self.isEmpty() else self.rear.data

    # Clear deque
    def erase(self):
        while not self.isEmpty():
            self.deleteFront()

# Driver code
if __name__ == '__main__':
    dq = myDeque()

    dq.insertRear(5)
    dq.insertRear(10)
    print("Rear:", dq.getRear())

    dq.deleteRear()
    print("New Rear:", dq.getRear())

    dq.insertFront(15)
    print("Front:", dq.getFront())
    print("Size:", dq.getSize())

    dq.deleteFront()
    print("New Front:", dq.getFront())
C#
using System;

// node of doubly linked list
public class node {
    public int data;
    public node prev, next;

    public node(int data) {
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

// deque implementation using doubly linked list
public class myDeque {
    private node front, rear;
    private int size;

    // constructor
    public myDeque() {
        front = rear = null;
        size = 0;
    }

    // check if deque is empty
    public bool isEmpty() {
        return front == null;
    }

    // get size of deque
    public int getSize() {
        return size;
    }

    // insert at front
    public void insertFront(int data) {
        node newNode = new node(data);
        if (isEmpty()) front = rear = newNode;
        else {
            newNode.next = front;
            front.prev = newNode;
            front = newNode;
        }
        size++;
    }

    // insert at rear
    public void insertRear(int data) {
        node newNode = new node(data);
        if (isEmpty()) front = rear = newNode;
        else {
            newNode.prev = rear;
            rear.next = newNode;
            rear = newNode;
        }
        size++;
    }

    // delete from front
    public void deleteFront() {
        if (isEmpty()) Console.WriteLine("UnderFlow");
        else {
            front = front.next;
            if (front != null) front.prev = null;
            else rear = null;
            size--;
        }
    }

    // delete from rear
    public void deleteRear() {
        if (isEmpty()) Console.WriteLine("UnderFlow");
        else {
            rear = rear.prev;
            if (rear != null) rear.next = null;
            else front = null;
            size--;
        }
    }

    // get front element
    public int getFront() {
        return isEmpty() ? -1 : front.data;
    }

    // get rear element
    public int getRear() {
        return isEmpty() ? -1 : rear.data;
    }

    // clear deque
    public void erase() {
        while (!isEmpty()) deleteFront();
    }
}

// driver code
class GfG {
    static void Main() {
        myDeque dq = new myDeque();
        dq.insertRear(5);
        dq.insertRear(10);
        Console.WriteLine("Rear: " + dq.getRear());
        dq.deleteRear();
        Console.WriteLine("New Rear: " + dq.getRear());

        dq.insertFront(15);
        Console.WriteLine("Front: " + dq.getFront());
        Console.WriteLine("Size: " + dq.getSize());

        dq.deleteFront();
        Console.WriteLine("New Front: " + dq.getFront());
    }
}
JavaScript
// node of doubly linked list
class node {
    constructor(data) {
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

// deque implementation using doubly linked list
class myDeque {
    constructor() {
        this.front = null;
        this.rear = null;
        this.size = 0;
    }

    // check if deque is empty
    isEmpty() {
        return this.front === null;
    }

    // get size of deque
    getSize() {
        return this.size;
    }

    // insert at front
    insertFront(data) {
        const newNode = new node(data);
        if (this.isEmpty()) {
            this.front = this.rear = newNode;
        } else {
            newNode.next = this.front;
            this.front.prev = newNode;
            this.front = newNode;
        }
        this.size++;
    }

    // insert at rear
    insertRear(data) {
        const newNode = new node(data);
        if (this.isEmpty()) {
            this.front = this.rear = newNode;
        } else {
            newNode.prev = this.rear;
            this.rear.next = newNode;
            this.rear = newNode;
        }
        this.size++;
    }

    // delete from front
    deleteFront() {
        if (this.isEmpty()) console.log("UnderFlow");
        else {
            this.front = this.front.next;
            if (this.front) this.front.prev = null;
            else this.rear = null;
            this.size--;
        }
    }

    // delete from rear
    deleteRear() {
        if (this.isEmpty()) console.log("UnderFlow");
        else {
            this.rear = this.rear.prev;
            if (this.rear) this.rear.next = null;
            else this.front = null;
            this.size--;
        }
    }

    // get front element
    getFront() {
        return this.isEmpty() ? -1 : this.front.data;
    }

    // get rear element
    getRear() {
        return this.isEmpty() ? -1 : this.rear.data;
    }

    // clear deque
    erase() {
        while (!this.isEmpty()) this.deleteFront();
    }
}

// Driver Code
const dq = new myDeque();
dq.insertRear(5);
dq.insertRear(10);
console.log("Rear:", dq.getRear());
dq.deleteRear();
console.log("New Rear:", dq.getRear());

dq.insertFront(15);
console.log("Front:", dq.getFront());
console.log("Size:", dq.getSize());

dq.deleteFront();
console.log("New Front:", dq.getFront());

Output
Rear: 10
New Rear: 5
Front: 15
Size: 2
New Front: 5
Comment