返回
双向链表与双向循环链表:从零开始理解数据结构
见解分享
2024-02-04 20:47:05
双向链表介绍
双向链表是在单向链表的基础上增加了一个指向前面节点的指针 prev,使得链表中的每个节点都具有指向后继节点的 next 指针和指向前驱节点的 prev 指针。这样,双向链表就可以实现正向和反向的遍历,更加灵活地访问和修改数据。
双向链表的应用非常广泛,常见于需要进行正反向遍历的场景,例如:
- 浏览器的前进和后退按钮
- 文本编辑器中的撤销和重做功能
- 操作系统中的进程管理
- 虚拟内存管理
- 文件系统中的索引
双向循环链表介绍
双向循环链表是在双向链表的基础上增加了一个指向头结点的指针 head,使得链表形成一个闭环。这样,双向循环链表可以实现无穷尽的遍历,并且在任何位置都可以进行插入和删除操作。
双向循环链表的应用也十分广泛,常见于需要进行循环遍历的场景,例如:
- 音乐播放器中的播放列表
- 游戏中的角色列表
- 操作系统中的任务队列
- 网络中的数据传输
双向链表与单向链表的比较
特点 | 单向链表 | 双向链表 |
---|---|---|
指针 | 每个节点只有一个指向后继节点的指针 | 每个节点有两个指针,一个指向后继节点,一个指向前驱节点 |
遍历 | 只支持单向遍历 | 支持正向和反向遍历 |
访问和修改数据 | 相对困难,需要从头结点开始遍历 | 更加灵活,可以从任何位置访问和修改数据 |
应用场景 | 前进和后退按钮、撤销和重做功能 | 浏览器的前进和后退按钮、文本编辑器中的撤销和重做功能、操作系统中的进程管理、虚拟内存管理、文件系统中的索引 |
双向循环链表与双向链表的比较
特点 | 双向链表 | 双向循环链表 |
---|---|---|
指针 | 每个节点有两个指针,一个指向后继节点,一个指向前驱节点 | 每个节点有两个指针,一个指向后继节点,一个指向前驱节点,还有一个指向头结点的指针 |
遍历 | 支持正向和反向遍历 | 支持无穷尽的遍历 |
插入和删除 | 可以从任何位置进行插入和删除 | 可以从任何位置进行插入和删除 |
应用场景 | 浏览器的前进和后退按钮、文本编辑器中的撤销和重做功能、操作系统中的进程管理、虚拟内存管理、文件系统中的索引 | 音乐播放器中的播放列表、游戏中的角色列表、操作系统中的任务队列、网络中的数据传输 |
双向链表和双向循环链表的实现
双向链表和双向循环链表的实现非常相似,主要区别在于双向循环链表在头结点和尾结点的处理上有所不同。
以下是用 C++ 实现的双向链表的代码:
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int data) {
this->data = data;
this->next = nullptr;
this->prev = nullptr;
}
};
class DoublyLinkedList {
public:
Node* head;
Node* tail;
DoublyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void insertAtHead(int data) {
Node* newNode = new Node(data);
if (this->head == nullptr) {
this->head = newNode;
this->tail = newNode;
} else {
newNode->next = this->head;
this->head->prev = newNode;
this->head = newNode;
}
}
void insertAtTail(int data) {
Node* newNode = new Node(data);
if (this->tail == nullptr) {
this->head = newNode;
this->tail = newNode;
} else {
this->tail->next = newNode;
newNode->prev = this->tail;
this->tail = newNode;
}
}
void deleteAtHead() {
if (this->head == nullptr) {
return;
}
if (this->head == this->tail) {
delete this->head;
this->head = nullptr;
this->tail = nullptr;
} else {
Node* newHead = this->head->next;
delete this->head;
this->head = newHead;
this->head->prev = nullptr;
}
}
void deleteAtTail() {
if (this->tail == nullptr) {
return;
}
if (this->head == this->tail) {
delete this->tail;
this->head = nullptr;
this->tail = nullptr;
} else {
Node* newTail = this->tail->prev;
delete this->tail;
this->tail = newTail;
this->tail->next = nullptr;
}
}
void printList() {
Node* current = this->head;
while (current != nullptr) {
cout << current->data << " ";
current = current->next;
}
cout << endl;
}
};
以下是用 C++ 实现的双向循环链表的代码:
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int data) {
this->data = data;
this->next = nullptr;
this->prev = nullptr;
}
};
class DoublyCircularLinkedList {
public:
Node* head;
DoublyCircularLinkedList() {
this->head = nullptr;
}
void insertAtHead(int data) {
Node* newNode = new Node(data);
if (this->head == nullptr) {
this->head = newNode;
newNode->next = newNode;
newNode->prev = newNode;
} else {
newNode->next = this->head;
newNode->prev = this->head->prev;
this->head->prev = newNode;
this->head = newNode;