C++双向循环链表类模版实例代码分析
发表于:2024-11-24 作者:千家信息网编辑
千家信息网最后更新 2024年11月24日,本文小编为大家详细介绍"C++双向循环链表类模版实例代码分析",内容详细,步骤清晰,细节处理妥当,希望这篇"C++双向循环链表类模版实例代码分析"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一
千家信息网最后更新 2024年11月24日C++双向循环链表类模版实例代码分析
本文小编为大家详细介绍"C++双向循环链表类模版实例代码分析",内容详细,步骤清晰,细节处理妥当,希望这篇"C++双向循环链表类模版实例代码分析"文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
1.插入某个节点流程
如下图所示:
对应代码如下所示:
/*插入一个新的节点*/ bool insert(int i, const T& value) { if (!((i>=0) && (i<=m_length))) { ThrowException("Invalid parameter i to get value ..."); return false; } Node* pre = getNode(i-1); Node* node = new Node(value); // new一个新节点 node->next = pre->next; // 将node新节点的next链接到下个节点 node->prev = pre; // 将node新节点的prev链接到pre上个节点 pre->next->prev = node; // 将下个节点的prev链接到node新节点 pre->next = node; // 将上个节点的next链接到node新节点 m_length +=1; return true; }
2.构造函数修改
在构造函数中,需要将头节点的next和prev都指向自己,从而实现一个闭环状态,代码如下所示:
LinkedList() { m_header.next = &m_header; m_header.prev = &m_header; m_length = 0; }
3.重新实现append和prepend函数
因为是个双向循环链表,所以我们很轻松的就能获取到表头节点和表尾节点,代码如下所示:
void append(const T &value) { Node* node = new Node(value); // new一个新节点 node->next = &m_header; // 新节点的下个节点为头节点 node->prev = m_header.prev; // 新节点的上个节点为末尾节点 node->prev->next = node; // 新节点的上个节点的下个节点为新节点 m_header.prev = node; // 开头节点的上个节点为i m_length +=1; } void prepend(const T &value) { Node* node = new Node(value); // new一个新节点 node->next = m_header.next; // 新节点的下个节点为头节点的next node->prev = &m_header; // 新节点的上个节点为头节点 m_header.next = node; // 设置头结点下个节点为node node->next->prev = node; // 设置之前的节点前驱节点 m_length +=1; }
4.修改迭代器类
由于现在是循环双链表,所以每个节点的next都是有值的,所以我们需要判断m_current当前指标是否等于头节点,如果等于则表示已经到链表末尾了.所以代码如下所示:
bool hasNext() { return (m_current && m_current != list->constHeader()); }
由于现在有prev成员,所以需要增加向前遍历函数:
void toEnd() { m_current = list->constHeader()->prev; }bool hasPrev() { return (m_current && m_current != list->constHeader()); }T& previous() { Node *ret = m_current; m_current = m_current->prev; return ret->value; }
5.LinkedList.h代码如下
#ifndef LinkedLIST_H#define LinkedLIST_H#include "throw.h"// throw.h里面定义了一个ThrowException抛异常的宏,如下所示://#include//using namespace std;//#define ThrowException(errMsg) {cout<<__FILE__<<" LINE"<<__LINE__<<": "< struct LinkedNode{ inline LinkedNode(){ } inline LinkedNode(const T &arg): value(arg) { } LinkedNode *prev; // 前驱结点 LinkedNode *next; // 后驱节点 T value; // 节点值};/*链表类模板*/template class LinkedList{protected: typedef LinkedNode Node; mutable Node m_header; // 头节点 int m_length;public: LinkedList() { m_header.next = &m_header; m_header.prev = &m_header; m_length = 0; } ~LinkedList() { clear(); } int length() {return m_length;} Node* begin() {return m_header.next;} inline Node* constHeader() const { return &m_header; } static bool rangeValid(int i,int len) {return ((i>=0) && (i next = &m_header; // 新节点的下个节点为头节点 node->prev = m_header.prev; // 新节点的上个节点为末尾节点 node->prev->next = node; // 新节点的上个节点的下个节点为新节点 m_header.prev = node; // 开头节点的上个节点为i m_length +=1; } void prepend(const T &value) { Node* node = new Node(value); // new一个新节点 node->next = m_header.next; // 新节点的下个节点为头节点的next node->prev = &m_header; // 新节点的上个节点为头节点 m_header.next = node; // 设置头结点下个节点为node node->next->prev = node; // 设置之前的节点前驱节点 m_length +=1; } /*获取i位置处的节点*/ Node* getNode(int i) { Node* ret = &m_header; while((i--)>-1) { // 由于有头节点所以,i为0时,其实ret = m_header->n ret = ret->next; } return ret; } /*插入一个新的节点*/ bool insert(int i, const T& value) { if (!((i>=0) && (i<=m_length))) { ThrowException("Invalid parameter i to get value ..."); return false; } Node* pre = getNode(i-1); Node* node = new Node(value); // new一个新节点 node->next = pre->next; // 将node新节点的next链接到下个节点 node->prev = pre; // 将node新节点的prev链接到pre上个节点 pre->next->prev = node; // 将下个节点的prev链接到node新节点 pre->next = node; // 将上个节点的next链接到node新节点 m_length +=1; return true; } /*删除一个节点*/ bool remove(int i) { if (!rangeValid(i, m_length)) { ThrowException("Invalid parameter i to get value ..."); return false; } Node* pre = getNode(i-1); Node* current = pre->next; // 获取要删除的节点 pre->next = current->next; // 将上个节点的next链接到前一个的next中 current->next->prev = pre; // 将下个节点的prev链接到pre节点 delete current; // delete空闲的节点 m_length -=1; return true; } /*获取节点数据*/ T get(int i) { T ret; if (!rangeValid(i, m_length)) { ThrowException("Invalid parameter i to get value ..."); } else { ret = getNode(i)->value; } return ret; } /*设置节点*/ bool set(int i, const T& value) { if (!rangeValid(i, m_length)) { ThrowException("Invalid parameter i to get value ..."); return false; } getNode(i)->value = value; return true; } void clear() { while(m_length > 0) { remove(0); } } LinkedList & operator << (const T& value) { append(value); return *this; } /*在链表中向前查找value所在的索引号.默认从from索引号0(表头)开始.如果未找到则返回-1.*/ int indexOf(const T &value, int from =0) { int ret = 0; Node* node = m_header.next; while(node) { if (ret >= from && node->value == value) { return ret; } node = node->next; ret+=1; } return -1; }};/*链表迭代器类模板*/template class LinkedListIterator{ typedef LinkedNode Node; LinkedList *list; Node *m_current; // 当前指标public: explicit LinkedListIterator(LinkedList &l):list(&l) { m_current = l.begin(); } void toBegin() { m_current = list->begin(); } void toEnd() { m_current = list->constHeader()->prev; } bool hasHeader() { return (m_current && m_current == list->constHeader()); } bool hasNext() { return (m_current && m_current != list->constHeader()); } T& next() { Node *ret = m_current; m_current = m_current->next; return ret->value; } bool hasPrev() { return (m_current && m_current != list->constHeader()); } T& previous() { Node *ret = m_current; m_current = m_current->prev; return ret->value; } T& value() { if (m_current == nullptr) { ThrowException(" Current value is empty ..."); } return m_current->value; } T& move(int i) { if (!list->rangeValid(i, list->length())) { ThrowException("Invalid parameter i to get value ..."); } m_current = list->getNode(i); return value(); }};#endif // LinkedLIST_H
6.测试运行
测试代码如下所示:
LinkedListlist; for(int i = 0; i< 5; i++) list.append(i); LinkedListIterator it(list); cout<<"list.length:"< 运行打印:
while循环打印30次,代码如下所示:
it.toBegin(); int i = 30; while(i--) { if (it.hasHeader()) it.next(); // 如果到头结点,需要舍弃掉 cout<<"i:"<读到这里,这篇"C++双向循环链表类模版实例代码分析"文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注行业资讯频道。
节点
代码
链接
结点
双向
环链
函数
实例
模版
C++
分析
前驱
指标
文章
末尾
模板
内容
开头
循环
测试
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
新加坡服务器怎么弄快
程序员与软件开发工程师
福州猎娱网络技术有限公司
即时通信软件开发开题报告
仙剑奇侠传五数据库
进化神经网络技术框架图学习
服务器主机网
衢州桌面软件开发项目
高速服务器加速
app定制软件开发服务企业
福建软件开发面试
幻塔官方和b站服务器相连吗
国内免费代理服务器APP
四年级网络安全的手抄报图片
人工智能怎么保持网络安全
泰安互联网科技公司
工控机串口服务器连接不上
重大网络安全事件情况说明
网络安全教育平台答案
预防沉迷网络安全图片
酒店管理系统数据库设计
app软件开发营销费用
青年应该怎么维护网络安全
黑客学网络安全的吗
杭州物联网软件开发公司
中专网络技术未来做什么
网络技术要看的书
法治日网络安全答题
vertx写游戏服务器
网络安全维护报告