Implementation of Deque using doubly linked list
A Deque (Double-Ended Queue) is a data structure that allows adding and removing elements from both the front and rear ends. Using a doubly linked list to implement a deque makes these operations very efficient, as each node in the list has pointers to both the previous and next nodes. This means we can insert and delete elements from both ends in constant time.
Operations on Deque
The following four basic operations are typically performed on a deque:
insertFront()
: Adds an item at the front of the deque.insertRear()
: Adds an item at the rear of the deque.deleteFront()
: Removes an item from the front of the deque.deleteRear()
: Removes an item from the rear of the deque.
Additionally, the following operations are also supported:
getFront()
: Retrieves the front item from the deque.getRear()
: Retrieves the last item from the deque.isEmpty()
: Checks if the deque is empty.size()
: Returns the number of elements in the deque.erase()
: Removes all elements from the deque.

Doubly Linked List Representation of Deque
For implementing deque, we need to keep track of two pointers, front and rear. We enqueue (push) an item at the rear or the front end of deque and dequeue(pop) an item from both rear and front end.
Working
Declare two pointers front and rear of type Node, where Node represents the structure of a node of a doubly linked list. Initialize both of them with value NULL.
Insertion at Front end
1. Allocate space for a newNode of doubly linked list.
2. IF newNode == NULL, then
3. print "Overflow"
4. ELSE
5. IF front == NULL, then
6. rear = front = newNode
7. ELSE
8. newNode->next = front
9. front->prev = newNode
10. front = newNode
Insertion at Rear end
1. Allocate space for a newNode of doubly linked list.
2. IF newNode == NULL, then
3. print "Overflow"
4. ELSE
5. IF rear == NULL, then
6. front = rear = newNode
7. ELSE
8. newNode->prev = rear
9. rear->next = newNode
10. rear = newNode
Deletion from Front end
1. IF front == NULL
2. print "Underflow"
3. ELSE
4. Initialize temp = front
5. front = front->next
6. IF front == NULL
7. rear = NULL
8. ELSE
9. front->prev = NULL
10 Deallocate space for temp
Deletion from Rear end
1. IF front == NULL
2. print "Underflow"
3. ELSE
4. Initialize temp = rear
5. rear = rear->prev
6. IF rear == NULL
7. front = NULL
8. ELSE
9. rear->next = NULL
10 Deallocate space for temp
#include <iostream>
using namespace std;
struct Node {
int data;
Node *prev, *next;
Node(int data) {
this->data = data;
prev = nullptr;
next = nullptr;
}
};
class Deque {
Node *front, *rear;
int size;
public:
Deque() { front = nullptr; rear = nullptr; size = 0; }
bool isEmpty() { return front == nullptr; }
int getSize() { return size; }
void insertFront(int data) {
Node* newNode = new Node(data);
if (isEmpty()) front = rear = newNode;
else {
newNode->next = front;
front->prev = newNode;
front = newNode;
}
size++;
}
void insertRear(int data) {
Node* newNode = new Node(data);
if (isEmpty()) front = rear = newNode;
else {
newNode->prev = rear;
rear->next = newNode;
rear = newNode;
}
size++;
}
void deleteFront() {
if (isEmpty()) cout << "UnderFlow\n";
else {
Node* temp = front;
front = front->next;
if (front) front->prev = nullptr;
else rear = nullptr;
delete temp;
size--;
}
}
void deleteRear() {
if (isEmpty()) cout << "UnderFlow\n";
else {
Node* temp = rear;
rear = rear->prev;
if (rear) rear->next = nullptr;
else front = nullptr;
delete temp;
size--;
}
}
int getFront() { return isEmpty() ? -1 : front->data; }
int getRear() { return isEmpty() ? -1 : rear->data; }
void clear() {
while (!isEmpty()) deleteFront();
}
};
int main() {
Deque 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>
struct Node {
int data;
struct Node *prev, *next;
};
struct Deque {
struct Node *front, *rear;
int size;
};
struct Deque* createDeque() {
struct Deque* dq = (struct Deque*)malloc(sizeof(struct Deque));
dq->front = dq->rear = NULL;
dq->size = 0;
return dq;
}
int isEmpty(struct Deque* dq) { return dq->front == NULL; }
int getSize(struct Deque* dq) { return dq->size; }
void insertFront(struct Deque* 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++;
}
void insertRear(struct Deque* dq, int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
if (isEmpty(dq)) dq->front = dq->rear = newNode;
else {
newNode->prev = dq->rear;
dq->rear->next = newNode;
dq->rear = newNode;
}
dq->size++;
}
void deleteFront(struct Deque* dq) {
if (isEmpty(dq)) printf("UnderFlow\n");
else {
struct Node* temp = dq->front;
dq->front = dq->front->next;
if (dq->front) dq->front->prev = NULL;
else dq->rear = NULL;
free(temp);
dq->size--;
}
}
void deleteRear(struct Deque* dq) {
if (isEmpty(dq)) printf("UnderFlow\n");
else {
struct Node* temp = dq->rear;
dq->rear = dq->rear->prev;
if (dq->rear) dq->rear->next = NULL;
else dq->front = NULL;
free(temp);
dq->size--;
}
}
int getFront(struct Deque* dq) { return isEmpty(dq) ? -1 : dq->front->data; }
int getRear(struct Deque* dq) { return isEmpty(dq) ? -1 : dq->rear->data; }
void clear(struct Deque* dq) {
while (!isEmpty(dq)) deleteFront(dq);
}
int main() {
struct Deque* dq = createDeque();
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));
clear(dq);
free(dq);
return 0;
}
import java.util.LinkedList;
import java.util.Deque;
public class DequeExample {
private LinkedList<Integer> deque;
public DequeExample() {
deque = new LinkedList<>();
}
public boolean isEmpty() { return deque.isEmpty(); }
public int getSize() { return deque.size(); }
public void insertFront(int data) {
deque.addFirst(data);
}
public void insertRear(int data) {
deque.addLast(data);
}
public void deleteFront() {
if (isEmpty()) System.out.println("UnderFlow");
else deque.removeFirst();
}
public void deleteRear() {
if (isEmpty()) System.out.println("UnderFlow");
else deque.removeLast();
}
public int getFront() { return isEmpty() ? -1 : deque.getFirst(); }
public int getRear() { return isEmpty() ? -1 : deque.getLast(); }
public void clear() { deque.clear(); }
public static void main(String[] args) {
DequeExample dq = new DequeExample();
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());
}
}
# Deque implementation in Python
class Node:
def __init__(self, data):
self.data = data
self.prev = None
self.next = None
class Deque:
def __init__(self):
self.front = None
self.rear = None
self.size = 0
def is_empty(self):
return self.front is None
def get_size(self):
return self.size
def insert_front(self, data):
new_node = Node(data)
if self.is_empty():
self.front = self.rear = new_node
else:
new_node.next = self.front
self.front.prev = new_node
self.front = new_node
self.size += 1
def insert_rear(self, data):
new_node = Node(data)
if self.is_empty():
self.front = self.rear = new_node
else:
new_node.prev = self.rear
self.rear.next = new_node
self.rear = new_node
self.size += 1
def delete_front(self):
if self.is_empty():
print("UnderFlow")
else:
temp = self.front
self.front = self.front.next
if self.front:
self.front.prev = None
else:
self.rear = None
del temp
self.size -= 1
def delete_rear(self):
if self.is_empty():
print("UnderFlow")
else:
temp = self.rear
self.rear = self.rear.prev
if self.rear:
self.rear.next = None
else:
self.front = None
del temp
self.size -= 1
def get_front(self):
return -1 if self.is_empty() else self.front.data
def get_rear(self):
return -1 if self.is_empty() else self.rear.data
def clear(self):
while not self.is_empty():
self.delete_front()
# Example usage
if __name__ == '__main__':
dq = Deque()
dq.insert_rear(5)
dq.insert_rear(10)
print("Rear:", dq.get_rear())
dq.delete_rear()
print("New Rear:", dq.get_rear())
dq.insert_front(15)
print("Front:", dq.get_front())
print("Size:", dq.get_size())
dq.delete_front()
print("New Front:", dq.get_front())
// Deque implementation in C#
using System;
public class Node {
public int data;
public Node prev, next;
public Node(int data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
public class Deque {
private Node front, rear;
private int size;
public Deque() {
front = rear = null;
size = 0;
}
public bool IsEmpty() {
return front == null;
}
public int GetSize() {
return size;
}
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++;
}
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++;
}
public void DeleteFront() {
if (IsEmpty()) Console.WriteLine("UnderFlow");
else {
Node temp = front;
front = front.next;
if (front != null) front.prev = null;
else rear = null;
temp = null;
size--;
}
}
public void DeleteRear() {
if (IsEmpty()) Console.WriteLine("UnderFlow");
else {
Node temp = rear;
rear = rear.prev;
if (rear != null) rear.next = null;
else front = null;
temp = null;
size--;
}
}
public int GetFront() {
return IsEmpty() ? -1 : front.data;
}
public int GetRear() {
return IsEmpty() ? -1 : rear.data;
}
public void Clear() {
while (!IsEmpty()) DeleteFront();
}
}
class Program {
static void Main() {
Deque dq = new Deque();
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());
}
}
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class Deque {
constructor() {
this.front = null;
this.rear = null;
this.size = 0;
}
isEmpty() {
return this.front === null;
}
getSize() {
return this.size;
}
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++;
}
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++;
}
deleteFront() {
if (this.isEmpty()) console.log("UnderFlow");
else {
const temp = this.front;
this.front = this.front.next;
if (this.front) this.front.prev = null;
else this.rear = null;
this.size--;
}
}
deleteRear() {
if (this.isEmpty()) console.log("UnderFlow");
else {
const temp = this.rear;
this.rear = this.rear.prev;
if (this.rear) this.rear.next = null;
else this.front = null;
this.size--;
}
}
getFront() {
return this.isEmpty() ? -1 : this.front.data;
}
getRear() {
return this.isEmpty() ? -1 : this.rear.data;
}
clear() {
while (!this.isEmpty()) this.deleteFront();
}
}
// Driver code
const dq = new Deque();
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
- Time Complexity : Time complexity of operations like insertFront(), insertRear(), deleteFront(), deleteRear() is O(1). The Time Complexity of erase() is O(n).
- Auxiliary space: O(1)