📅  最后修改于: 2023-12-03 15:10:19.967000             🧑  作者: Mango
双链表(Doubly linked list)是一种使用了两个指向相邻节点的指针的链表数据结构。与单链表不同的是,双链表中的每个节点除了有一个指向下一个节点的指针以外,还有一个指向前一个节点的指针。这样除了可以向前遍历,也能向后遍历。
template <typename T>
struct DListNode {
T data;
DListNode* prev;
DListNode* next;
DListNode(T data = T{}, DListNode* prev = nullptr, DListNode* next = nullptr)
: data(data), prev(prev), next(next) {}
};
template <typename T>
class DoublyLinkedList {
public:
DoublyLinkedList() : head_(new DListNode<T>()), tail_(new DListNode<T>()) {
head_->next = tail_;
tail_->prev = head_;
}
// 头插法
void PushFront(const T& data) {
DListNode<T>* node = new DListNode<T>(data, head_, head_->next);
head_->next->prev = node;
head_->next = node;
}
// 尾插法
void PushBack(const T& data) {
DListNode<T>* node = new DListNode<T>(data, tail_->prev, tail_);
tail_->prev->next = node;
tail_->prev = node;
}
// 删除节点
void Remove(DListNode<T>* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
delete node;
}
// 清空链表
void Clear() {
DListNode<T>* cur = head_->next;
while (cur != tail_) {
DListNode<T>* del = cur;
cur = cur->next;
delete del;
}
// 重新初始化头节点和尾节点,指向彼此
head_->next = tail_;
tail_->prev = head_;
}
// 获取链表长度
int Size() const {
int count = 0;
DListNode<T>* cur = head_->next;
while (cur != tail_) {
++count;
cur = cur->next;
}
return count;
}
// 判断是否为空
bool Empty() const { return head_->next == tail_; }
// 获取第 k 个节点的数据,k 取值从 0 开始
T& Get(int k) const {
DListNode<T>* cur = head_->next;
while (k-- && cur != tail_) {
cur = cur->next;
}
return cur->data;
}
// 获取第一个节点
T& Front() const { return head_->next->data; }
// 获取最后一个节点
T& Back() const { return tail_->prev->data; }
// 打印链表
void Print() const {
DListNode<T>* cur = head_->next;
while (cur != tail_) {
std::cout << cur->data << ' ';
cur = cur->next;
}
std::cout << '\n';
}
private:
DListNode<T>* head_; // 头节点,指向链表的头部哨兵节点
DListNode<T>* tail_; // 尾节点,指向链表的尾部哨兵节点
};
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 尾插法插入元素,结果为 5 4 3 2 1 6 7 8 9 10
for (int i = 6; i <= 10; ++i) {
list.PushBack(i);
}
list.Print();
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 删除第 3 个节点,结果为 5 4 2 1
list.Remove(list.Get(2));
list.Print();
// 删除第 1 个节点,结果为 4 2 1
list.Remove(list.Get(0));
list.Print();
// 删除最后一个节点,结果为 4 2
list.Remove(list.Get(1));
list.Print();
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 清空链表
list.Clear();
std::cout << "链表已清空,长度为:" << list.Size() << '\n';
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 链表长度为 5
std::cout << "链表长度为:" << list.Size() << '\n';
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 判断链表是否为空,结果为 true
if (list.Empty()) {
std::cout << "链表为空\n";
}
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 判断链表是否为空,结果为 false
if (!list.Empty()) {
std::cout << "链表不为空\n";
}
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 获取第 2 个节点的数据,结果为 4
std::cout << "第 2 个节点的数据为:" << list.Get(1) << '\n';
// 获取第 5 个节点的数据,结果为 1
std::cout << "第 5 个节点的数据为:" << list.Get(4) << '\n';
return 0;
}
#include "doubly_linked_list.h"
int main() {
DoublyLinkedList<int> list;
// 头插法插入元素,结果为 5 4 3 2 1
for (int i = 1; i <= 5; ++i) {
list.PushFront(i);
}
list.Print();
// 获取第一个节点的数据,结果为 5
std::cout << "第一个节点的数据为:" << list.Front() << '\n';
// 获取最后一个节点的数据,结果为 1
std::cout << "最后一个节点的数据为:" << list.Back() << '\n';
return 0;
}