Topics
In a Doubly Linked List (DLL) each node contains a data field, a reference to the next node in the sequence (next), and a reference to the preceding node in the sequence (prev). There are a couple of standard implementations:
- Using just a
head
pointer ( time to insert/delete at the end) - Using both
head
andtail
pointers (constant time to insert/deletion at end)- If
tail
isn’t available explicitly, one can loop till the last node of the list:Node* tail = head; while (tail->next) tail = tail->next;
- If
#include <iostream>
template <typename T>
class DoublyLinkedList {
private:
struct Node {
T data;
Node* next;
Node* prev;
Node(const T& value) : data(value), next(nullptr), prev(nullptr) {}
};
Node* head;
Node* tail;
size_t size;
public:
// Constructor and Destructor
DoublyLinkedList() : head(nullptr), tail(nullptr), size(0) {}
~DoublyLinkedList() {
clear();
}
// Insertion operations
void insertFront(const T& value) {
Node* newNode = new Node(value);
if (empty()) {
head = tail = newNode;
} else {
newNode->next = head;
head->prev = newNode;
head = newNode;
}
size++;
}
void insertBack(const T& value) {
Node* newNode = new Node(value);
if (empty()) {
head = tail = newNode;
} else {
newNode->prev = tail;
tail->next = newNode;
tail = newNode;
}
size++;
}
// Deletion operations
void deleteFront() {
if (empty()) return;
Node* temp = head;
head = head->next;
if (head) {
head->prev = nullptr;
} else {
tail = nullptr;
}
delete temp;
size--;
}
void deleteBack() {
if (empty()) return;
Node* temp = tail;
tail = tail->prev;
if (tail) {
tail->next = nullptr;
} else {
head = nullptr;
}
delete temp;
size--;
}
bool deleteValue(const T& value) {
if (empty()) return false;
if (head->data == value) {
deleteFront();
return true;
}
if (tail->data == value) {
deleteBack();
return true;
}
Node* current = head;
while (current && current->data != value) {
current = current->next;
}
if (!current) return false;
current->prev->next = current->next;
current->next->prev = current->prev;
delete current;
size--;
return true;
}
// Search and lookup operations
Node* search(const T& value) const {
Node* current = head;
while (current && current->data != value) {
current = current->next;
}
return current;
}
Node* getHead() const { return head; }
Node* getTail() const { return tail; }
// Utility functions
bool empty() const { return size == 0; }
size_t getSize() const { return size; }
void clear() {
while (!empty()) {
deleteFront();
}
}
void print() const {
Node* current = head;
while (current) {
std::cout << current->data;
if (current->next) std::cout << " <-> ";
current = current->next;
}
std::cout << std::endl;
}
};