26 Star 369 Fork 112

cyberdash / 数据结构(C++模板实现)

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
circular_doubly_linked_list.h 25.72 KB
一键复制 编辑 原始数据 按行查看 历史
Y_Dash 提交于 2023-06-18 14:18 . 线性表完善doxygen
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
/*!
* @file circular_doubly_linked_list.h
* @author CyberDash计算机考研, cyberdash@163.com(抖音id:cyberdash_yuan)
* @brief 双向循环链表
* @version 0.9.0
* @date 2020-07-28
*/
#ifndef CYBER_DASH_CIRCULAR_DOUBLY_LINKED_LIST_H
#define CYBER_DASH_CIRCULAR_DOUBLY_LINKED_LIST_H
#include <iostream>
#include <cstddef>
#include "linear_list.h"
/*!
* @brief **双向循环链表结点模板结构体**
* @tparam TData 数据项类型模板参数
*/
template <typename TData>
struct CircularDoublyLinkedNode {
/*!
* @brief **构造函数(下一结点/前一节点)**
* @param next 下一结点(指针)
* @param prev 上一结点(指针)
*/
explicit CircularDoublyLinkedNode(CircularDoublyLinkedNode<TData>* next = NULL,
CircularDoublyLinkedNode<TData>* prev = NULL)
: next(next), prev(prev) {}
/*!
* @brief **构造函数(数据项/前一结点/前一结点)**
* @param data 数据项
* @param next 下一结点(指针)
* @param prev 上一结点(指针)
*/
explicit CircularDoublyLinkedNode(const TData& data,
CircularDoublyLinkedNode<TData>* next = NULL,
CircularDoublyLinkedNode<TData>* prev = NULL)
: data(data), next(next), prev(prev) {}
TData data; //!< 数据项
CircularDoublyLinkedNode<TData>* next; //!< 下一结点
CircularDoublyLinkedNode<TData>* prev; //!< 上一结点
};
/*!
* @brief **循环双向链表模板类**
* @tparam TData 数据项类型模板参数
* @note
* 循环双向链表模板类
* ---------------
* ---------------
*
* ---------------
*/
template<typename TData>
class CircularDoublyLinkedList: public LinearList<TData> {
public:
/*! @brief **默认构造函数** */
CircularDoublyLinkedList(): first_(NULL), length_(0) {}
// 析构函数
~CircularDoublyLinkedList();
/*! @brief **长度** */
int Length() const { return this->length_; }
/*! @brief **判断是否为空链表** */
bool IsEmpty() const { return this->first_ == NULL; }
// 清空
void Clear();
/*! @brief **获取链表首结点** */
CircularDoublyLinkedNode<TData>* First() const { return this->first_; }
// 搜索
CircularDoublyLinkedNode<TData>* Search(const TData& data);
// 获取结点(按方向)
CircularDoublyLinkedNode<TData>* GetNodeByDirection(int step, int direction);
// 获取结点
CircularDoublyLinkedNode<TData>* GetNode(int pos);
// 插入结点
bool Insert(int prev_pos, const TData& data);
// 删除结点(按方向)
bool RemoveByDirection(int step, TData& data, int direction);
// 删除结点
bool Remove(int target_pos, TData& data);
// 获取结点数据
bool GetData(int pos, TData& data) const;
// 设置结点数据
bool SetData(int pos, const TData& data);
// 打印
void Print();
static const int BACKWARD_DIRECTION = 0; //!< **prev方向**
static const int FORWARD_DIRECTION = 1; //!< **next方向**
private:
CircularDoublyLinkedNode<TData>* first_; //!< **首元素结点(指针)**
int length_; //!< **长度**
};
/*!
* @brief **清空**
* @note
* 清空
* ---
* ---
*
* <span style="color:#FF8100">
* one by one
* </span>
*
* ---
* + **1 释放结点内存**\n\n
* **while** first_(首元素结点)不为NULL:\n\n
* &emsp; <span style="color:#003153">(首结点调整)\n</span>
* &emsp; 声明cur_target_node(本轮删除的结点), 指向first_\n
* &emsp; first_指向cur->next\n\n
* &emsp; 释放cur_target_node指向的结点\n
* &emsp; cur_target_node置NULL\n\n
* + **2 调整长度**\n\n
* length_设置为0\n
*
*
* ---
*/
template<typename TData>
void CircularDoublyLinkedList<TData>::Clear() {
// ---------- 1 释放结点内存 ----------
while (first_ != NULL) { // while first_(首元素结点)不为NULL
// (删除当前首结点)
CircularDoublyLinkedNode<TData>* cur_target_node = this->first_; // 声明cur_target_node(本轮删除的结点), 指向first_
first_ = cur_target_node->next; // first_指向cur->next
delete cur_target_node; // 释放cur_target_node指向的结点
cur_target_node = NULL; // target_node置NULL
}
// ---------- 2 调整长度 ----------
this->length_ = 0; // length_设置为0
}
/*!
* @brief **析构函数**
* @tparam TData 数据项类型模板参数
* @note
* 析构函数
* -------
* -------
*
* -------
* 调用Clear()函数\n
*
*
* -------
*/
template<typename TData>
CircularDoublyLinkedList<TData>::~CircularDoublyLinkedList() {
this->Clear();
}
/*!
* @brief **搜索**
* @param data 数据项
* @return 结点指针
* @note
* 搜索
* ---
* ---
*
* ---
* 初始化cur(遍历指针), 指向first_(首个结点)\n\n
* **for loop** 遍历链表每个结点, 从pos(位置)等于1开始, 每次遍历结束cur指向自身next :\n
* **if** cur->data等于参数data :\n
* &emsp; 返回cur\n\n
* 返回NULL(没有对应结点)\n
*
*
* ---
*/
template<typename TData>
CircularDoublyLinkedNode<TData>* CircularDoublyLinkedList<TData>::Search(const TData& data) {
CircularDoublyLinkedNode<TData>* cur = this->first_; // 初始化cur(遍历指针), 指向first_(首个结点)
for (int pos = 1; pos <= this->Length(); pos++, cur = cur->next) { // for loop 遍历链表每个结点, 从pos(位置)等于1开始, 每次遍历结束cur指向自身next
if (cur->data == data) { // if cur->data等于参数data
return cur; // 返回cur
}
}
return NULL; // 返回NULL(没有对应结点)
}
/*!
* @brief **获取结点(按方向)**
* @param step 步数
* @param direction 方向
* @return 结点指针
* @note
* 获取结点(按方向)
* --------------
* --------------
*
* <span style="color:#FF8100">
* CircularDoublyLinkedList::BACKWARD_DIRECTION, 向prev指针方向\n
* CircularDoublyLinkedList::FORWARD_DIRECTION, 向next指针方向\n
* </span>
*
* --------------
* + **1 非法步数处理** \n\n
* **if** step < 0 || step >= 链表长度 :\n
* &emsp; 返回NULL\n\n
* + **2 按方向遍历至pos位置** \n\n
* 初始化cur(遍历指针), 指向first_(首结点) \n\n
* **for loop** 循环step次 :\n
* &emsp; **if** 向prev方向 :\n
* &emsp;&emsp; cur指向cur->prev\n
* &emsp; **else** (向next方向) :\n
* &emsp;&emsp; cur指向cur->next\n\n
* + **3 返回结果** \n\n
* 返回cur\n
*
*
* --------------
*/
template<typename TData>
CircularDoublyLinkedNode<TData>* CircularDoublyLinkedList<TData>::GetNodeByDirection(int step, int direction) {
// ---------- 1 非法步数处理 ----------
if (step < 0 || step >= length_) { // if step < 0 || step >= 链表长度
return NULL; // 返回NULL
}
// ---------- 2 按方向遍历至pos位置 ----------
CircularDoublyLinkedNode<TData>* cur = first_; // 初始化cur(遍历指针), 指向first_(首结点)
for (int i = 1; i <= step; i++) { // for loop 循环step次
if (direction == BACKWARD_DIRECTION) { // if 向prev方向
cur = cur->prev; // cur指向cur->prev
} else { // else (向next方向)
cur = cur->next; // cur指向cur->next
}
}
// ---------- 3 返回结果 ----------
return cur; // 返回cur
}
/*!
* @brief **获取结点**
* @tparam TData 数据项类型模板参数
* @param pos 位置
* @return 结点指针
* 获取结点
* -------------------
* -------------------
*
* -------------------
* + **1 pos为0情况处理**\n\n
* **if** pos等于0 :\n
* &emsp; 返回first_->prev\n\n
* + **2 调用GetDataByDirection**\n\n
* 计算step = pos - 1\n
* 按照FORWARD_DIRECTION方向, 调用GetDataByDirection\n
*
*
* -------------------
*/
template<typename TData>
CircularDoublyLinkedNode<TData>* CircularDoublyLinkedList<TData>::GetNode(int pos) {
// ---------- 1 pos为0情况处理 ----------
if (pos == 0) { // if pos等于0
return first_->prev; // 返回first_->prev
}
// ---------- 2 调用GetDataByDirection ----------
int step = pos - 1; // 计算step = pos - 1
return this->GetNodeByDirection(step, CircularDoublyLinkedList::FORWARD_DIRECTION); // next方向, 调用GetDataByDirection
}
/*!
* @brief **插入结点**
* @tparam TData 数据项类型模板参数
* @param prev_pos 位置
* @param data 数据
* @return 执行结果
* 插入结点
* -------
* -------
*
* 在pos位置之后的位置插入
*
* -------
* + **1 非法位置判断**\n\n
* **if** prev_pos < 0 || prev_pos > 链表长度 :\n
* &emsp; 返回false\n\n
* + **2 构造插入结点**\n\n
* 分配内存并初始化插入结点\n
* **if** 内存分配失败 :\n
* &emsp; 抛出bad_alloc()\n\n
* + **3 空链表插入**\n\n
* **if** 空链表 :\n
* &emsp; first_指向new_node\n\n
* &emsp; new_node->next指向自身\n
* &emsp; new_node->prev指向自身\n
* &emsp; 链表长度设置为1\n\n
* &emsp; 返回true\n\n
* + **4 插入**\n\n
* <span style="color:#003153">4.1 获取prev_node(指向插入位置前一位置结点的指针)\n</span>
* 调用GetNode获取prev_node\n\n
* <span style="color:#003153">4.2 插入\n</span>
* 插入结点的next, 指向插入结点的前一结点的next\n
* 插入结点的前一结点的next, 指向插入结点\n\n
* 插入结点的下一结点的prev, 指向插入结点\n
* 插入结点的prev, 指向插入结点的前一结点\n\n
* <span style="color:#003153">4.3 插入结点作为首结点的情况\n</span>
* **if** prev_pos为0(插入结点作为首结点) :\n
* &emsp; first_指向新插入的结点\n\n
* <span style="color:#003153">4.4 调整长度\n</span>
* length_加1\n\n
* + **5 返回**\n\n
* 返回true\n
*
*
* -------
*/
template<typename TData>
bool CircularDoublyLinkedList<TData>::Insert(int prev_pos, const TData& data) {
// ---------- 1 非法位置判断 ----------
if (prev_pos < 0 || prev_pos > length_) { // if prev_pos < 0 || prev_pos > 链表长度
return false; // 返回false
}
// ---------- 2 构造插入结点 ----------
CircularDoublyLinkedNode<TData>* new_node = new CircularDoublyLinkedNode<TData>(data); // 分配内存并初始化插入结点
if (new_node == NULL) { // if 内存分配失败
throw bad_alloc(); // 抛出bad_alloc()
}
// ---------- 3 空链表插入 ----------
if (first_ == NULL) { // if 空链表
first_ = new_node; // first_指向new_node
new_node->next = new_node; // new_node->next指向自身
new_node->prev = new_node; // new_node->prev指向自身
this->length_ = 1; // 链表长度设置为1
return true; // 返回true
}
// ---------- 4 插入 ----------
// -- 4.1 获取prev_node(指向插入位置前一位置结点的指针) --
CircularDoublyLinkedNode<TData>* prev_node = this->GetNode(prev_pos); // 调用GetNode获取prev_node
// -- 4.2 插入 --
new_node->next = prev_node->next; // 插入结点的next, 指向插入结点的前一结点的next
prev_node->next = new_node; // 插入结点的前一结点的next, 指向插入结点
new_node->next->prev = new_node; // 插入结点的下一结点的prev, 指向插入结点
new_node->prev = prev_node; // 插入结点的prev, 指向插入结点的前一结点
// -- 4.3 插入结点作为首结点的情况 --
if (prev_pos == 0) { // if prev_pos为0(插入结点作为首结点)
first_ = new_node; // first_指向新插入的结点
}
// -- 4.4 调整长度 --
this->length_++; // length_加1
// ---------- 5 返回 ----------
return true; // 返回true
}
/*!
* @brief **删除(结点)元素(按方向)**
* @tparam TData 数据项类型模板参数
* @param step 步数
* @param data 数据项保存变量
* @param direction 方向
* @return 执行结果
* @note
* 删除(结点)元素(按方向)
* -------------------
* -------------------
*
* -------------------
* + **1 非法情况处理**\n
* **if** first_为NULL :\n
* &emsp; 返回false\n\n
* + **2 获取结点指针**\n
* 调用GetNodeByDirection, 获取target_node(指向待删除结点的指针)\n
* **if** target_node为NULL :\n
* &emsp; 返回false\n\n
* + **3 只有1个结点的情况处理**\n\n
* **if** 链表长度为1 :\n
* &emsp; target_node的data赋给参数data\n\n
* &emsp; 释放target_node\n
* &emsp; target_node置NULL\n\n
* &emsp; length_设为0\n\n
* &emsp; 返回true\n\n
* + **4 删除**\n\n
* <span style="color:#FF7638">4.1 如果删除首结点, first_调整\n</span>
* **if** 删除首结点 :\n
* &emsp; **if** next方向 :\n
* &emsp;&emsp; first_指向target_node->next\n
* &emsp; **else if** next方向 :\n
* &emsp;&emsp; first_指向target_node->next\n\n
* <span style="color:#FF7638">4.2 删除操作\n</span>
* target_node的下一结点的prev, 指向target_node的前一结点\n
* target_node的前一结点的prev, 指向target_node的下一结点\n\n
* target_node的data, 赋给参数data\n\n
* 释放target_node\n
* target_node置为NULL\n\n
* <span style="color:#FF7638">4.3 调整长度\n</span>
* 链表长度减1\n\n
* + **5 返回结果**\n\n
* 返回true\n
*
*
* -------------------
*/
template<typename TData>
bool CircularDoublyLinkedList<TData>::RemoveByDirection(int step, TData &data, int direction) {
// --------- 1 非法情况处理 ---------
if (first_ == NULL) { // if first_为NULL
return false; // 返回false
}
// --------- 2 获取结点指针 ---------
CircularDoublyLinkedNode<TData>* target_node = GetNodeByDirection(step, direction); // 调用GetNodeByDirection, 获取target_node(指向待删除结点的指针)
if (target_node == NULL) { // if target_node为NULL
return false; // 返回false
}
// --------- 3 只有1个结点的情况处理 ---------
if (length_ == 1) { // if 链表长度为1
data = target_node->data; // target_node的data赋给参数data
delete target_node; // 释放target_node
this->first_ = NULL; // target_node置NULL
length_ = 0; // length_设为0
return true; // 返回true
}
// --------- 4 删除 ---------
// ( 4.1 如果删除首结点, first_调整 )
if (target_node == first_) { // if 删除首结点
if (direction == FORWARD_DIRECTION) { // if next方向
first_ = target_node->next; // first_指向target_node->next
} else if (direction == BACKWARD_DIRECTION) { // else if next方向
first_ = target_node->prev; // first_指向target_node->next
}
}
// ( 4.2 删除操作 )
target_node->next->prev = target_node->prev; // target_node的下一结点的prev, 指向target_node的前一结点
target_node->prev->next = target_node->next; // target_node的前一结点的prev, 指向target_node的下一结点
data = target_node->data; // target_node的data, 赋给参数data
delete target_node; // 释放target_node
target_node = NULL; // target_node置为NULL
// ( 4.3 调整长度 )
this->length_--; // 链表长度减1
// --------- 5 返回结果 ---------
return true; // 返回true
}
/*!
* @brief **删除结点**
* @tparam TData 数据项类型模板参数
* @param target_pos 待删除结点位置
* @param data 数据项保存变量
* @return 执行结果
* @note
* 删除结点
* ------
* ------
*
* ------
* 初始化step等于target_pos - 1\n
* 调用RemoveByDirection, 返回执行结果\n
*
*
* ------
*/
template<typename TData>
bool CircularDoublyLinkedList<TData>::Remove(int target_pos, TData& data) {
int step = target_pos - 1; // 初始化step等于target_pos - 1
return this->RemoveByDirection(step, data, CircularDoublyLinkedList::FORWARD_DIRECTION); // 调用RemoveByDirection, 返回执行结果
}
/*!
* @brief **获取结点数据**
* @tparam TData 数据项类型模板参数
* @param pos 位置
* @param data 数据项保存变量
* @return 执行结果
* @note
* 获取结点数据
* ----------
* ----------
*
* 不推荐调用GetData(0)
*
* ----------
* + **1 非法情况处理**\n
* **if** pos < 1 || pos > 链表长度 || 空链表 :\n
* &emsp; 返回false\n\n
* + **2 pos为0情况处理**\n
* **if** pos为0 :\n
* &emsp; first->prev->data赋给参数data\n
* &emsp; 返回true\n\n
* + **3 遍历至pos位置结点**\n
* 初始化cur(遍历指针), 指向首结点\n
* **for loop** 遍历pos - 1次 :\n
* &emsp; cur指向cur->next\n\n
* + **4 赋值**\n
* cur->data赋给参数data\n\n
* + **5 退出函数**\n
* 返回true\n
*
*
* ----------
*/
template<typename TData>
bool CircularDoublyLinkedList<TData>::GetData(int pos, TData& data) const {
// ---------- 1 非法情况处理 ----------
if (pos < 0 || pos > length_ || length_ == 0) { // if pos < 1 || pos > 链表长度 || 空链表
return false; // 返回false
}
// ---------- 2 pos为0情况处理 ----------
if (pos == 0) { // if pos为0
data = first_->prev->data; // first->prev->data赋给参数data
return true; // 返回true
}
// ---------- 3 遍历至pos位置结点 ----------
CircularDoublyLinkedNode<TData>* cur = this->first_; // 初始化cur(遍历指针), 指向首结点
for (int i = 1; i < pos; i++) { // for loop 遍历pos - 1次
cur = cur->next; // cur指向cur->next
}
// ---------- 4 赋值 ----------
data = cur->data; // cur->data赋给参数data
// ---------- 5 退出函数 ----------
return true; // 返回true
}
/*!
* @brief **设置结点数据**
* @tparam TData 数据项类型模板参数
* @param pos 位置
* @param data 数据项
* @return 执行结果
* @note
* 设置结点数据
* ----------
* ----------
*
* ----------
* + **1 非法情况处理**\n\n
* **if** pos < 1 || pos > 链表长度 :\n
* &emsp; 返回false\n\n
* + **2 遍历至pos位置结点**\n\n
* 初始化cur(遍历指针), 指向首结点\n
* **for loop** 遍历pos - 1次 :\n
* &emsp; cur指向cur->next\n\n
* + **3 赋值**\n\n
* 参数data赋给cur->data\n\n
* + **4 退出函数**\n\n
* 返回true\n
*
*
* ----------
*/
template<typename TData>
bool CircularDoublyLinkedList<TData>::SetData(int pos, const TData& data) {
// ---------- 1 非法情况处理 ----------
if (pos < 1 || pos > Length()) { // if pos < 1 || pos > 链表长度
return false; // 返回false
}
// ---------- 2 遍历至pos位置结点 ----------
CircularDoublyLinkedNode<TData>* cur = this->first_; // 初始化cur(遍历指针), 指向首结点
for (int i = 1; i < pos; i++) { // for loop 遍历pos - 1次
cur = cur->next; // cur指向cur->next
}
// ---------- 3 赋值 ----------
cur->data = data; // 参数data, 赋给cur->data
// ---------- 4 退出函数 ----------
return true; // 返回true
}
/*!
* @brief **打印**
* @tparam TData 数据项类型模板参数
* @note
* 打印
* ---
* ---
*
* ---
* + **1 空链表处理**\n
* **if** 空链表 :\n
* &emsp; 打印"Empty list"\n
* &emsp; 退出函数\n
* + **2 forward方向打印**\n
* 打印 "next方向(forward)遍历打印:"\n
* 初始化cur(遍历指针), 指向first_\n
* **for loop** 从位置1开始, next方向遍历链表 :\n
* &emsp; 打印当前结点data和';'\n
* &emsp; cur指向下一结点\n
* **for loop** 从位置1开始, prev方向遍历链表 :\n
* &emsp; 打印当前结点data和';'\n
* &emsp; cur指向前一结点\n
*
*
* ---
*/
template<typename TData>
void CircularDoublyLinkedList<TData>::Print() {
// ---------- 1 空链表处理 ----------
if (this->first_ == NULL) { // if 空链表
cout << "Empty list" << endl; // 打印"Empty list"
return; // 退出函数
}
// ---------- 2 forward方向打印 ----------
cout << "next方向(forward)遍历打印:" << endl; // 打印 "next方向(forward)遍历打印:"
CircularDoublyLinkedNode<TData>* cur = this->First(); // 初始化cur(遍历指针), 指向first_
for (int pos = 1; pos <= Length(); pos++) { // for loop 从位置1开始, next方向遍历链表
cout << cur->data << "; "; // 打印当前结点data和';'
cur = cur->next; // cur指向下一结点
}
cout << endl;
cout << "prev方向(backward)遍历打印:" << endl;
for (int pos = 1; pos <= Length(); pos++) { // for loop 从位置1开始, prev方向遍历链表
cout << cur->data << "; "; // 打印当前结点data和';'
cur = cur->prev; // cur指向前一结点
}
cout << endl;
}
#endif // CYBER_DASH_CIRCULAR_DOUBLY_LINKED_LIST_H
C++
1
https://gitee.com/cyberdash/data-structures-cpp.git
git@gitee.com:cyberdash/data-structures-cpp.git
cyberdash
data-structures-cpp
数据结构(C++模板实现)
master

搜索帮助