Implementation of Deque using doubly linked list
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.

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.
Doubly Linked List Representation of Deque:
- Define a Doubly Linked List Node structure containing, data, prev and next
- Declare two pointers, front and rear, of type Node and initialize both as NULL to represent an empty deque.
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;
}
}
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;
}
}
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
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;
}
}
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class myDeque {
constructor() {
this.front = this.rear = null;
}
}
Insertion at Front :
- Allocate a new node (newNode) for the doubly linked list.
- Check if the deque is empty:
=> If front == NULL, set both front and rear to newNode. - 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).
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;
}
}
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;
}
}
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
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;
}
}
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 :
- Allocate a new node (newNode) for the doubly linked list.
- Check if the deque is empty:
=> If rear == NULL, set both front and rear to newNode. - 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).
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;
}
}
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;
}
}
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
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;
}
}
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 :
- Check if the deque is empty:
=> If front == NULL, print "Underflow" and exit. - Store the current front node:
=> temp = front - Move the front pointer to the next node:
=> front = front->next - 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 - Deallocate memory of the removed node:
=> delete temp (or equivalent in your language)
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--;
}
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;
}
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
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;
}
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 :
- Check if the deque is empty:
=> front == NULL (or rear == NULL), print "Underflow" and exit. - Store the current rear node:
=> temp = rear - Move the rear pointer to the previous node:
=> rear = rear->prev - 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 - Deallocate memory of the removed node:
=> delete temp (or equivalent in your language)
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--;
}
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;
}
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
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;
}
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:
#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;
}
#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;
}
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());
}
}
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())
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());
}
}
// 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