Description: A dequeuer, more commonly referred to as a deque (pronounced "deck"), is a double-ended queue that allows insertion and deletion of elements from both the front and the back. This flexibility makes deques more versatile than standard queues, which only allow operations at one end.
Deques can be implemented using:
Here’s a simple C++ implementation of a deque using a doubly linked list:
#include <iostream>
using namespace std;
// Node structure for doubly linked list
struct Node {
int data;
Node* prev;
Node* next;
};
// Deque class
class Deque {
private:
Node* front;
Node* rear;
int size;
public:
Deque() : front(nullptr), rear(nullptr), size(0) {}
// Add an element at the front
void enqueueFront(int value) {
Node* newNode = new Node{value, nullptr, front};
if (front) {
front->prev = newNode;
}
front = newNode;
if (!rear) {
rear = front; // If the deque was empty, rear is also the new node
}
size++;
}
// Add an element at the back
void enqueueBack(int value) {
Node* newNode = new Node{value, rear, nullptr};
if (rear) {
rear->next = newNode;
}
rear = newNode;
if (!front) {
front = rear; // If the deque was empty, front is also the new node
}
size++;
}
// Remove an element from the front
int dequeueFront() {
if (isEmpty()) {
throw runtime_error("Deque is empty");
}
int value = front->data; // Get the data from the front node
Node* temp = front;
front = front->next;
if (front) {
front->prev = nullptr; // Update the new front's previous pointer
} else {
rear = nullptr; // If deque is now empty, update rear as well
}
delete temp;
size--;
return value;
}
// Remove an element from the back
int dequeueBack() {
if (isEmpty()) {
throw runtime_error("Deque is empty");
}
int value = rear->data; // Get the data from the rear node
Node* temp = rear;
rear = rear->prev;
if (rear) {
rear->next = nullptr; // Update the new rear's next pointer
} else {
front = nullptr; // If deque is now empty, update front as well
}
delete temp;
size--;
return value;
}
// Peek at the front element
int peekFront() {
if (isEmpty()) {
throw runtime_error("Deque is empty");
}
return front->data;
}
// Peek at the back element
int peekBack() {
if (isEmpty()) {
throw runtime_error("Deque is empty");
}
return rear->data;
}
// Check if the deque is empty
bool isEmpty() {
return size == 0;
}
// Get the size of the deque
int getSize() {
return size;
}
~Deque() {
while (!isEmpty()) {
dequeueFront(); // Dequeue all elements to free memory
}
}
};
int main() {
Deque dq;
// Adding elements
dq.enqueueBack(10);
dq.enqueueBack(20);
dq.enqueueFront(5);
dq.enqueueFront(2);
cout << "Front element: " << dq.peekFront() << endl; // Should print 2
cout << "Back element: " << dq.peekBack() << endl; // Should print 20
cout << "Dequeued from front: " << dq.dequeueFront() << endl; // Should remove 2
cout << "Dequeued from back: " << dq.dequeueBack() << endl; // Should remove 20
cout << "Size of deque: " << dq.getSize() << endl; // Should print 2
return 0;
}
Deques provide a flexible way to manage data with operations available at both ends, making them useful in various applications such as task scheduling, caching, and implementing algorithms that require efficient access to both ends of a data structure. Understanding how to implement and use deques is essential for effective problem-solving in programming.
Open this section to load past papers