您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# C++双向链表怎么实现
## 1. 双向链表概述
双向链表(Doubly Linked List)是链表的一种重要变体,与单向链表相比,每个节点不仅包含指向下一个节点的指针,还包含指向前一个节点的指针。这种结构使得双向链表在操作上更加灵活,能够高效地进行双向遍历。
### 1.1 基本特点
- **前驱和后继指针**:每个节点包含`prev`和`next`两个指针
- **双向遍历**:可以从头到尾或从尾到头遍历链表
- **内存开销**:比单向链表多一个指针的空间开销
- **操作复杂度**:某些操作(如删除指定节点)时间复杂度更低
### 1.2 与单向链表的对比
| 特性 | 单向链表 | 双向链表 |
|----------------|--------------|----------------|
| 指针数量 | 1个(next) | 2个(prev, next) |
| 遍历方向 | 只能单向 | 可以双向 |
| 删除指定节点复杂度 | O(n) | O(1) |
| 内存占用 | 较少 | 较多 |
## 2. 节点结构设计
### 2.1 基础节点类
```cpp
template <typename T>
class Node {
public:
T data; // 数据域
Node<T>* prev; // 前驱指针
Node<T>* next; // 后继指针
// 构造函数
Node(const T& value) : data(value), prev(nullptr), next(nullptr) {}
};
为了增强通用性,我们使用模板类:
template <typename T>
struct ListNode {
T val;
ListNode* prev;
ListNode* next;
// 默认构造函数
ListNode() : val(T()), prev(nullptr), next(nullptr) {}
// 带值构造函数
ListNode(T x) : val(x), prev(nullptr), next(nullptr) {}
// 完整构造函数
ListNode(T x, ListNode* p, ListNode* n) : val(x), prev(p), next(n) {}
};
template <typename T>
class DoublyLinkedList {
private:
Node<T>* head; // 头指针
Node<T>* tail; // 尾指针
size_t size; // 链表长度
public:
// 构造函数和析构函数
DoublyLinkedList();
~DoublyLinkedList();
// 基本操作
bool isEmpty() const;
size_t getSize() const;
// 插入操作
void insertFront(const T& value);
void insertBack(const T& value);
void insertAt(const T& value, size_t position);
// 删除操作
void removeFront();
void removeBack();
void removeAt(size_t position);
void removeValue(const T& value);
// 查找操作
bool contains(const T& value) const;
T getFront() const;
T getBack() const;
T getAt(size_t position) const;
// 遍历操作
void displayForward() const;
void displayBackward() const;
// 清空链表
void clear();
};
// 构造函数
template <typename T>
DoublyLinkedList<T>::DoublyLinkedList() : head(nullptr), tail(nullptr), size(0) {}
// 析构函数
template <typename T>
DoublyLinkedList<T>::~DoublyLinkedList() {
clear();
}
template <typename T>
void DoublyLinkedList<T>::insertFront(const T& value) {
Node<T>* newNode = new Node<T>(value);
if (isEmpty()) {
head = tail = newNode;
} else {
newNode->next = head;
head->prev = newNode;
head = newNode;
}
size++;
}
template <typename T>
void DoublyLinkedList<T>::insertBack(const T& value) {
Node<T>* newNode = new Node<T>(value);
if (isEmpty()) {
head = tail = newNode;
} else {
tail->next = newNode;
newNode->prev = tail;
tail = newNode;
}
size++;
}
template <typename T>
void DoublyLinkedList<T>::insertAt(const T& value, size_t position) {
if (position > size) {
throw std::out_of_range("Position out of range");
}
if (position == 0) {
insertFront(value);
} else if (position == size) {
insertBack(value);
} else {
Node<T>* current = head;
for (size_t i = 0; i < position - 1; ++i) {
current = current->next;
}
Node<T>* newNode = new Node<T>(value);
newNode->next = current->next;
newNode->prev = current;
current->next->prev = newNode;
current->next = newNode;
size++;
}
}
template <typename T>
void DoublyLinkedList<T>::removeFront() {
if (isEmpty()) {
throw std::runtime_error("List is empty");
}
Node<T>* temp = head;
if (head == tail) { // 只有一个节点
head = tail = nullptr;
} else {
head = head->next;
head->prev = nullptr;
}
delete temp;
size--;
}
template <typename T>
void DoublyLinkedList<T>::removeBack() {
if (isEmpty()) {
throw std::runtime_error("List is empty");
}
Node<T>* temp = tail;
if (head == tail) { // 只有一个节点
head = tail = nullptr;
} else {
tail = tail->prev;
tail->next = nullptr;
}
delete temp;
size--;
}
template <typename T>
void DoublyLinkedList<T>::removeAt(size_t position) {
if (position >= size) {
throw std::out_of_range("Position out of range");
}
if (position == 0) {
removeFront();
} else if (position == size - 1) {
removeBack();
} else {
Node<T>* current = head;
for (size_t i = 0; i < position; ++i) {
current = current->next;
}
current->prev->next = current->next;
current->next->prev = current->prev;
delete current;
size--;
}
}
template <typename T>
bool DoublyLinkedList<T>::contains(const T& value) const {
Node<T>* current = head;
while (current != nullptr) {
if (current->data == value) {
return true;
}
current = current->next;
}
return false;
}
template <typename T>
T DoublyLinkedList<T>::getAt(size_t position) const {
if (position >= size) {
throw std::out_of_range("Position out of range");
}
Node<T>* current = head;
for (size_t i = 0; i < position; ++i) {
current = current->next;
}
return current->data;
}
template <typename T>
class DoublyLinkedListIterator {
private:
Node<T>* current;
public:
DoublyLinkedListIterator(Node<T>* node) : current(node) {}
// 前置++
DoublyLinkedListIterator& operator++() {
current = current->next;
return *this;
}
// 后置++
DoublyLinkedListIterator operator++(int) {
DoublyLinkedListIterator temp = *this;
current = current->next;
return temp;
}
// 前置--
DoublyLinkedListIterator& operator--() {
current = current->prev;
return *this;
}
// 后置--
DoublyLinkedListIterator operator--(int) {
DoublyLinkedListIterator temp = *this;
current = current->prev;
return temp;
}
T& operator*() const {
return current->data;
}
bool operator==(const DoublyLinkedListIterator& other) const {
return current == other.current;
}
bool operator!=(const DoublyLinkedListIterator& other) const {
return !(*this == other);
}
};
template <typename T>
class DoublyLinkedListReverseIterator {
private:
Node<T>* current;
public:
DoublyLinkedListReverseIterator(Node<T>* node) : current(node) {}
// 前置++
DoublyLinkedListReverseIterator& operator++() {
current = current->prev;
return *this;
}
// 其他操作与正向迭代器类似...
};
template <typename K, typename V>
class LRUCache {
private:
struct CacheNode {
K key;
V value;
CacheNode* prev;
CacheNode* next;
CacheNode(K k, V v) : key(k), value(v), prev(nullptr), next(nullptr) {}
};
std::unordered_map<K, CacheNode*> cacheMap;
CacheNode* head;
CacheNode* tail;
int capacity;
void moveToHead(CacheNode* node) {
if (node == head) return;
// 从当前位置移除节点
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
// 如果节点是尾节点,更新尾指针
if (node == tail) tail = node->prev;
// 将节点移动到头部
node->next = head;
node->prev = nullptr;
if (head) head->prev = node;
head = node;
// 如果链表为空,更新尾指针
if (!tail) tail = head;
}
public:
LRUCache(int cap) : capacity(cap), head(nullptr), tail(nullptr) {}
V get(K key) {
if (cacheMap.find(key) == cacheMap.end()) {
return V(); // 返回默认值
}
CacheNode* node = cacheMap[key];
moveToHead(node);
return node->value;
}
void put(K key, V value) {
if (cacheMap.find(key) != cacheMap.end()) {
CacheNode* node = cacheMap[key];
node->value = value;
moveToHead(node);
return;
}
// 创建新节点
CacheNode* newNode = new CacheNode(key, value);
cacheMap[key] = newNode;
// 添加到头部
if (!head) {
head = tail = newNode;
} else {
newNode->next = head;
head->prev = newNode;
head = newNode;
}
// 检查容量
if (cacheMap.size() > capacity) {
// 移除尾节点
cacheMap.erase(tail->key);
CacheNode* toDelete = tail;
tail = tail->prev;
if (tail) tail->next = nullptr;
delete toDelete;
if (!tail) head = nullptr;
}
}
};
操作 | 时间复杂度 |
---|---|
头部插入/删除 | O(1) |
尾部插入/删除 | O(1) |
指定位置插入/删除 | O(n) |
查找 | O(n) |
随机访问 | O(n) |
#include <mutex>
template <typename T>
class ThreadSafeDoublyLinkedList {
private:
DoublyLinkedList<T> list;
mutable std::mutex mtx;
public:
void insertFront(const T& value) {
std::lock_guard<std::mutex> lock(mtx);
list.insertFront(value);
}
// 其他线程安全封装方法...
};
可视化打印:实现链表的图形化输出
完整性检查:
bool checkIntegrity() const {
if (head == nullptr) return tail == nullptr;
Node<T>* current = head;
size_t count = 0;
while (current != nullptr) {
if (current->next != nullptr && current->next->prev != current) {
return false;
}
count++;
current = current->next;
}
return count == size;
}
本文详细介绍了C++中双向链表的实现方法,包括: - 基础节点结构设计 - 完整的双向链表类实现 - 各种插入、删除、查找操作 - 迭代器实现 - 实际应用案例(LRU缓存) - 性能优化和线程安全考虑
双向链表作为一种基础数据结构,在需要频繁双向遍历和中间插入删除的场景下表现出色。理解其实现原理对于掌握更复杂的数据结构(如哈希链表、跳表等)具有重要意义。
”`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。