用C++实现一个基于模板的双向循环链表并加上详细的注释
时间: 2024-01-22 20:18:56 浏览: 82
C++实现双向循环链表
以下是一个基于模板的双向循环链表的实现,代码中包含详细注释,可以帮助你更好地理解:
```cpp
#include <iostream>
using namespace std;
// 定义节点结构体
template <typename T>
struct Node {
T data;
Node<T>* prev;
Node<T>* next;
Node(const T& d, Node<T>* p = nullptr, Node<T>* n = nullptr)
: data(d), prev(p), next(n) {}
};
// 定义双向循环链表类
template <typename T>
class DoubleLinkedList {
public:
// 构造函数
DoubleLinkedList();
// 复制构造函数
DoubleLinkedList(const DoubleLinkedList& rhs);
// 移动构造函数
DoubleLinkedList(DoubleLinkedList&& rhs) noexcept;
// 赋值运算符
DoubleLinkedList& operator=(const DoubleLinkedList& rhs);
// 移动赋值运算符
DoubleLinkedList& operator=(DoubleLinkedList&& rhs) noexcept;
// 析构函数
~DoubleLinkedList();
// 获取链表长度
int size() const;
// 判断链表是否为空
bool empty() const;
// 获取第一个节点的数据
T& front();
const T& front() const;
// 获取最后一个节点的数据
T& back();
const T& back() const;
// 插入数据到链表头部
void push_front(const T& value);
// 插入数据到链表尾部
void push_back(const T& value);
// 删除第一个节点
void pop_front();
// 删除最后一个节点
void pop_back();
// 在指定位置插入数据
void insert(int pos, const T& value);
// 删除指定位置的节点
void erase(int pos);
// 清空链表
void clear();
// 打印链表元素
void print() const;
private:
int m_size; // 链表长度
Node<T>* head; // 头指针
Node<T>* tail; // 尾指针
// 初始化链表
void init();
// 复制链表
void copy(const DoubleLinkedList& rhs);
};
// 初始化链表
template <typename T>
void DoubleLinkedList<T>::init() {
m_size = 0;
head = tail = new Node<T>(T(), nullptr, nullptr); // 创建一个头节点
head->prev = tail; // 头节点前驱指向尾节点
head->next = tail; // 头节点后继指向尾节点
}
// 复制链表
template <typename T>
void DoubleLinkedList<T>::copy(const DoubleLinkedList& rhs) {
init(); // 初始化当前链表
Node<T>* p = rhs.head->next;
while (p != rhs.tail) { // 遍历rhs链表
push_back(p->data); // 将rhs链表中节点的数据插入到当前链表中
p = p->next;
}
}
// 构造函数
template <typename T>
DoubleLinkedList<T>::DoubleLinkedList() {
init(); // 初始化链表
}
// 复制构造函数
template <typename T>
DoubleLinkedList<T>::DoubleLinkedList(const DoubleLinkedList& rhs) {
copy(rhs); // 复制链表
}
// 移动构造函数
template <typename T>
DoubleLinkedList<T>::DoubleLinkedList(DoubleLinkedList&& rhs) noexcept
: m_size(rhs.m_size), head(rhs.head), tail(rhs.tail) {
rhs.m_size = 0;
rhs.head = rhs.tail = nullptr;
}
// 赋值运算符
template <typename T>
DoubleLinkedList<T>& DoubleLinkedList<T>::operator=(const DoubleLinkedList& rhs) {
if (this != &rhs) { // 判断是否为自赋值
clear(); // 清空当前链表
copy(rhs); // 复制链表
}
return *this;
}
// 移动赋值运算符
template <typename T>
DoubleLinkedList<T>& DoubleLinkedList<T>::operator=(DoubleLinkedList&& rhs) noexcept {
if (this != &rhs) { // 判断是否为自赋值
clear(); // 清空当前链表
m_size = rhs.m_size;
head = rhs.head;
tail = rhs.tail;
rhs.m_size = 0;
rhs.head = rhs.tail = nullptr;
}
return *this;
}
// 析构函数
template <typename T>
DoubleLinkedList<T>::~DoubleLinkedList() {
clear(); // 清空链表
delete head; // 释放头节点
}
// 获取链表长度
template <typename T>
int DoubleLinkedList<T>::size() const {
return m_size;
}
// 判断链表是否为空
template <typename T>
bool DoubleLinkedList<T>::empty() const {
return m_size == 0;
}
// 获取第一个节点的数据
template <typename T>
T& DoubleLinkedList<T>::front() {
return head->next->data;
}
template <typename T>
const T& DoubleLinkedList<T>::front() const {
return head->next->data;
}
// 获取最后一个节点的数据
template <typename T>
T& DoubleLinkedList<T>::back() {
return tail->prev->data;
}
template <typename T>
const T& DoubleLinkedList<T>::back() const {
return tail->prev->data;
}
// 插入数据到链表头部
template <typename T>
void DoubleLinkedList<T>::push_front(const T& value) {
Node<T>* p = new Node<T>(value, head, head->next); // 创建一个新节点
head->next->prev = p; // 原头节点的后继节点的前驱指向新节点
head->next = p; // 头节点的后继指向新节点
++m_size; // 链表长度加1
}
// 插入数据到链表尾部
template <typename T>
void DoubleLinkedList<T>::push_back(const T& value) {
Node<T>* p = new Node<T>(value, tail->prev, tail); // 创建一个新节点
tail->prev->next = p; // 原尾节点的前驱节点的后继指向新节点
tail->prev = p; // 尾节点的前驱指向新节点
++m_size; // 链表长度加1
}
// 删除第一个节点
template <typename T>
void DoubleLinkedList<T>::pop_front() {
if (!empty()) { // 判断链表是否为空
Node<T>* p = head->next; // 暂存头节点的后继节点
head->next = p->next; // 头节点的后继指向第二个节点
p->next->prev = head; // 第二个节点的前驱指向头节点
delete p; // 释放第一个节点的内存空间
--m_size; // 链表长度减1
}
}
// 删除最后一个节点
template <typename T>
void DoubleLinkedList<T>::pop_back() {
if (!empty()) { // 判断链表是否为空
Node<T>* p = tail->prev; // 暂存尾节点的前驱节点
tail->prev = p->prev; // 尾节点的前驱指向倒数第二个节点
p->prev->next = tail; // 倒数第二个节点的后继指向尾节点
delete p; // 释放最后一个节点的内存空间
--m_size; // 链表长度减1
}
}
// 在指定位置插入数据
template <typename T>
void DoubleLinkedList<T>::insert(int pos, const T& value) {
if (pos >= 0 && pos <= m_size) { // 判断pos是否合法
if (pos == 0) { // 如果pos为0,则插入到链表头部
push_front(value);
} else if (pos == m_size) { // 如果pos为m_size,则插入到链表尾部
push_back(value);
} else { // 否则在指定位置插入数据
Node<T>* p = head->next;
for (int i = 0; i < pos; ++i) {
p = p->next;
}
Node<T>* q = new Node<T>(value, p->prev, p); // 创建一个新节点
p->prev->next = q; // 插入节点的前驱节点的后继指向新节点
p->prev = q; // 插入节点的后继节点的前驱指向新节点
++m_size; // 链表长度加1
}
}
}
// 删除指定位置的节点
template <typename T>
void DoubleLinkedList<T>::erase(int pos) {
if (pos >= 0 && pos < m_size) { // 判断pos是否合法
if (pos == 0) { // 如果pos为0,则删除链表头部节点
pop_front();
} else if (pos == m_size - 1) { // 如果pos为m_size-1,则删除链表尾部节点
pop_back();
} else { // 否则删除指定位置的节点
Node<T>* p = head->next;
for (int i = 0; i < pos; ++i) {
p = p->next;
}
p->prev->next = p->next; // 待删除节点的前驱节点的后继指向待删除节点的后继节点
p->next->prev = p->prev; // 待删除节点的后继节点的前驱指向待删除节点的前驱节点
delete p; // 释放待删除节点的内存空间
--m_size; // 链表长度减1
}
}
}
// 清空链表
template <typename T>
void DoubleLinkedList<T>::clear() {
while (!empty()) { // 循环删除链表中的所有节点
pop_front();
}
}
// 打印链表元素
template <typename T>
void DoubleLinkedList<T>::print() const {
Node<T>* p = head->next;
while (p != tail) { // 遍历链表
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
```
使用示例:
```cpp
int main() {
DoubleLinkedList<int> list; // 创建一个双向循环链表
list.push_back(1); // 在尾部插入数据1
list.push_back(2); // 在尾部插入数据2
list.push_front(0); // 在头部插入数据0
list.insert(2, 3); // 在第2个位置插入数据3
list.erase(1); // 删除第1个节点
list.print(); // 打印链表元素
return 0;
}
```
阅读全文