数据结构与算法学习笔记之线性表五---循环链表的表示和实现(C++)
目录
前言
1.双向链表的定义
2.双向链表的表示和实现
1.定义
2.初始化
3.销毁
4.清空
5.表长
6.获取数据元素
7.前驱节点
8.后继节点
9.插入
10.删除
11.遍历
12.完整代码
前言
记录下双向链表的表示和实现。
1.循环链表的定义
循环链表(circular linked list)是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。由此,从表中任一结点出发均可找到表中其他结点,如图 2.12所示为单链的循环链表。类似地,还可以有多重链的循环链表。。
2.循环链表的表示和实现
1.定义
typedef int Status;
typedef int ElemType;
// 定义循环链表
typedef struct CircularNode {ElemType data; // 数据域struct CircularNode * next; // 直接后继
}CircularNode,*CircularLinkedList;
2.初始化
初始化双向链表,next指针指向自己。
// 初始化循环链表
Status initCircularLinkedList(CircularLinkedList &circularLinkedList){circularLinkedList = new CircularNode;if (!circularLinkedList) {//内存分配失败return 0;}circularLinkedList->next = circularLinkedList; // 将头节点的指针指向自身,形成循环return 1;
}
3.销毁
// 循环链表销毁
void destroyCircularLinkedList(CircularLinkedList &circularLinkedList) {if (!circularLinkedList) {return; // 链表为空,无需销毁}CircularLinkedList current = circularLinkedList->next; // 从第一个节点开始while (current != circularLinkedList) { // 遍历至头节点CircularLinkedList temp = current; // 暂存当前节点current = current->next; // 移动到下一个节点delete temp; // 释放当前节点内存}delete circularLinkedList; // 释放头节点内存circularLinkedList = nullptr; // 头指针置为空
}
4.清空
// 循环链表清空
void clearCircularLinkedList(CircularLinkedList &circularLinkedList) {if (!circularLinkedList) {return; // 链表为空,无需清空}CircularLinkedList current = circularLinkedList->next; // 从第一个节点开始while (current != circularLinkedList) { // 遍历至头节点CircularLinkedList temp = current; // 暂存当前节点current = current->next; // 移动到下一个节点delete temp; // 释放当前节点内存}circularLinkedList->next = circularLinkedList; // 头节点的 next 指针指向自身,链表置为空链表
}
5.表长
// 循环链表表长
int getCircularLinkedListLength(CircularLinkedList &circularLinkedList) {int length = 0;CircularNode *p = circularLinkedList->next; // 从第一个节点开始计数while (p != circularLinkedList) { // 当指针指向头节点时结束循环++length;p = p->next;}return length;
}
6.获取数据元素
// 获取循环链表中的元素
Status getCircularLinkedListElement(CircularLinkedList &circularLinkedList, int position, int *element) {if (position < 1 || position > getCircularLinkedListLength(circularLinkedList)) { // 非法位置return 0;}CircularNode *p = circularLinkedList->next; // 从第一个节点开始遍历int index = 1;while (index < position) { // 定位到指定位置p = p->next;index++;}*element = p->data; // 将节点的数据域值赋给 elementreturn 1;
}
7.前驱节点
// 获取循环链表中的第一个与element相同的元素的直接前驱
Status priorCircularLinkedListElement(CircularLinkedList &circularLinkedList, int element, int *priorElement) {if (isCircularLinkedListEmpty(circularLinkedList)) { // 空链表return 0;}CircularNode *p = circularLinkedList->next;CircularNode *pre = circularLinkedList; // 前驱节点do {if (p->data == element) { // 找到要查找的节点*priorElement = pre->data;return 1;}pre = p;p = p->next;} while (p != circularLinkedList->next); // 循环直到回到起始节点return 0; // 未找到相同元素
}
8.后继节点
先判断循环链表是否是空链表,然后遍历删除节点。
// 获取循环链表中的第一个与element相同的元素的后继节点
Status nextCircularLinkedListElement(CircularLinkedList &circularLinkedList, int element, int *nextElement) {if (isCircularLinkedListEmpty(circularLinkedList)) { // 空链表return 0;}CircularNode *p = circularLinkedList->next;do {if (p->data == element) { // 找到要查找的节点*nextElement = p->next->data;return 1;}p = p->next;} while (p != circularLinkedList->next); // 循环直到回到起始节点return 0; // 未找到相同元素
}
9.插入
首先判断插入位置是否合法,然后分别处理头结点和非头结点的情况。
// 循环链表插入
Status insertCircularLinkedList(CircularLinkedList &circularLinkedList, int i, int element) {if (i < 1) { // 插入位置非法return 0;}CircularNode *newNode = new CircularNode; // 新节点if (!newNode) { // 内存分配失败return 0;}newNode->data = element;if (i == 1) { // 插入到表头if (circularLinkedList == nullptr) { // 空链表newNode->next = newNode; // 自己指向自己circularLinkedList = newNode;} else {CircularNode *last = circularLinkedList;while (last->next != circularLinkedList) { // 找到最后一个节点last = last->next;}newNode->next = circularLinkedList; // 新节点指向表头last->next = newNode; // 最后一个节点指向新节点circularLinkedList = newNode; // 更新表头指针}} else { // 插入到非表头位置CircularNode *p = circularLinkedList;int j = 1;while (p->next != circularLinkedList && j < i - 1) { // 找到插入位置的前一个节点p = p->next;++j;}if (j < i - 1) { // 插入位置超出链表长度delete newNode;return 0;}newNode->next = p->next; // 新节点指向原来位置节点p->next = newNode; // 前一个节点指向新节点}return 1;
}
10.删除
首先判断删除位置是否合法,然后分别处理头结点和非头结点的情况。
// 循环链表删除
Status deleteCircularLinkedList(CircularLinkedList &circularLinkedList, int position, ElemType *deletedElement) {if (position < 1 || circularLinkedList == nullptr) { // 删除位置非法或链表为空return 0;}if (position == 1) { // 删除表头节点CircularNode *temp = circularLinkedList;*deletedElement = temp->data; // 存储被删除节点的数据if (circularLinkedList->next == circularLinkedList) { // 链表只有一个节点delete temp;circularLinkedList = nullptr;} else {CircularNode *last = circularLinkedList;while (last->next != circularLinkedList) { // 找到最后一个节点last = last->next;}last->next = circularLinkedList->next; // 最后一个节点指向第二个节点circularLinkedList = circularLinkedList->next; // 更新表头指针delete temp; // 释放被删除节点的内存}} else { // 删除非表头节点CircularNode *p = circularLinkedList;int j = 1;while (p->next != circularLinkedList && j < position - 1) { // 找到要删除节点的前一个节点p = p->next;++j;}if (j < position - 1 || p->next == circularLinkedList) { // 删除位置超出范围return 0;}CircularNode *temp = p->next; // 要删除的节点*deletedElement = temp->data; // 存储被删除节点的数据p->next = temp->next; // 前一个节点指向后一个节点delete temp; // 释放被删除节点的内存}return 1;
}
11.遍历
遍历循环链表
// 遍历循环链表
void traverseCircularLinkedList(CircularLinkedList &circularLinkedList) {if (circularLinkedList == nullptr) { // 空链表return;}CircularNode *p = circularLinkedList;do {cout << p->data << "\t"; // 输出当前节点的数据p = p->next; // 移动到下一个节点} while (p != circularLinkedList); // 循环直到回到起始节点cout << endl;
}
12.测试代码
void testCircularLinkedList(void) {CircularLinkedList circularLinkedList;cout<<"\n**********\t循环链表初始化\t**********"<<endl;if (initCircularLinkedList(circularLinkedList)) {cout<<"顺序表初始化成功"<<endl;}cout<<"\n**********\t循环链表判空和长度计算\t**********"<<endl;if (isCircularLinkedListEmpty(circularLinkedList)) {cout<<"循环链表为空,长度为"<<getCircularLinkedListLength(circularLinkedList)<<endl;}cout<<"\n**********\t循环链表插入测试\t**********"<<endl;for (int i = 1; i <=11 ; i++) {if (insertCircularLinkedList(circularLinkedList,i, i)) {cout<<"数据元素"<<i<<"插入成功"<<endl;}else{cout<<"数据元素"<<i<<"插入失败"<<endl;}}traverseCircularLinkedList(circularLinkedList);cout<<"\n**********\t循环链表根据下标获取数据元素测试\t**********"<<endl;for (int i = 0; i <= 12 ; i++) {int element;if (getCircularLinkedListElement(circularLinkedList,i, &element)) {cout<<"第"<<i<<"个数据元素为"<<element<<endl;}else{cout<<"第"<<i<<"个数据元素不存在"<<endl;}}cout<<"插入之后的循环链表"<<endl;traverseCircularLinkedList(circularLinkedList);cout<<"\n**********\t循环链表删除测试\t**********"<<endl;ElemType element;if (deleteCircularLinkedList(circularLinkedList, 11, &element)){cout<<"数据元素"<<element<<"删除成功"<<endl;}cout<<"删除之后的循环链表"<<endl;traverseCircularLinkedList(circularLinkedList);cout<<"\n**********\t循环链表后继节点测试\t**********"<<endl;int nextArr[3] = {1,8,11};for (int i = 0; i < 3; i++) {ElemType nextElement;if (nextCircularLinkedListElement(circularLinkedList, nextArr[i], &nextElement)) {cout<<"数据元素"<<nextArr[i]<<"后继节点为:"<<nextElement<<endl;}else{cout<<"数据元素"<<nextArr[i]<<"后继节点不存在"<<endl;}}cout<<"\n**********\t循环链表前驱节点测试\t**********"<<endl;int priorArr[3] = {8,11,1};for (int i = 0; i < 3; i++) {ElemType priorElement;if (priorCircularLinkedListElement(circularLinkedList, priorArr[i], &priorElement)) {cout<<"数据元素"<<priorArr[i]<<"前驱节点为"<<priorElement<<endl;}else{cout<<"数据元素"<<priorArr[i]<<"前驱节点不存在"<<endl;}}cout<<"\n**********\t循环链表销毁\t**********"<<endl;destroyCircularLinkedList(circularLinkedList);cout<<"循环链表销毁"<<endl;}
相关文章:
数据结构与算法学习笔记之线性表五---循环链表的表示和实现(C++)
目录 前言 1.双向链表的定义 2.双向链表的表示和实现 1.定义 2.初始化 3.销毁 4.清空 5.表长 6.获取数据元素 7.前驱节点 8.后继节点 9.插入 10.删除 11.遍历 12.完整代码 前言 记录下双向链表的表示和实现。 1.循环链表的定义 循环链表(circular linked list)…...
微信小程序生命周期揭秘:从启动到消亡的全过程剖析【附代码】
微信小程序生命周期揭秘:从启动到消亡的全过程剖析 一、小程序生命周期概览核心生命周期函数 二、深入理解生命周期回调2.1 onLoad: 首次亮相的准备2.2 onShow: 重登舞台的瞬间2.3 onReady: 舞台就绪,静待表演2.4 onHide & onUnload: 谨慎离场&#…...
Linux 下载 miniconda
https://repo.anaconda.com/miniconda/ 下载对应版本: wget -c https://repo.anaconda.com/miniconda/Miniconda3-py310_24.3.0-0-Linux-x86_64.sh给下载的文件添加可执行权限 chmod x Miniconda3-py310_24.3.0-0-Linux-x86_64.sh安装 ./Miniconda3-py310_24.3.…...
第十五篇:全面防护:构建不容侵犯的数据库安全策略与实战指南
全面防护:构建不容侵犯的数据库安全策略与实战指南 1. 引言:数据库安全的现代战略 1.1 简介:数据库安全在当今的数字化时代中的重要性 在数字化的浪潮中,数据已成为企业乃至国家的核心资产,其价值不亚于实体世界的黄…...
电脑快速搜索文件及文件夹软件——Everything
一、前言 Everything是一款由voidtools开发的文件搜索工具,主要运行于Windows操作系统上。它的主要功能是快速、高效地搜索电脑上的文件和文件夹名称。Everything通过利用NTFS文件系统的MFT(主文件表)来索引文件,从而实现几乎实时…...
02-登录页面、动态路由、权限等模块开发
权限模块开发流程 前端login页面开发后端SpringSecurity配置后端login接口开发前端页面框架搭建前端路由守卫,状态管理开发前后端完成认证流程 开发Login页面 创建Login页面创建router,可以跳转到Login页面 Login页面 使用element-plus开发 认证功…...
万物生长大会 | 创邻科技再登杭州准独角兽榜单
近日,由民建中央、中国科协指导,民建浙江省委会、中国投资发展促进会联合办的第八届万物生长大会在杭州举办。 在这场创新创业领域一年一度的盛会上,杭州市创业投资协会联合微链共同发布《2024杭州独角兽&准独角兽企业榜单》。榜单显示&…...
(六)Linux的Shell编程(上)
一.Shell Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。Ken Thompson 的 sh 是第一种 Unix Shell,Windows …...
CANopen总线_CANOpen开源协议栈
CANopen是自动化中使用的嵌入式系统的通信协议栈和设备配置文件规范。就OSI 模型而言,CANopen 实现了以上各层,包括网络层。 CANopen 标准由一个寻址方案、几个小型通信协议和一个由设备配置文件定义的应用层组成。通信协议支持网络管理、设备监控和节点…...
Rust 语言不支持 goto 语句
一、Rust 不提供 goto 语句 Rust 语言并没有提供 goto 语句。goto 语句在很多现代编程语言中已经不再被推荐使用,因为它可能导致代码的流程变得难以跟踪和理解,特别是在复杂的程序中。Rust 语言设计者选择了更加结构化和可预测的控制流语句,…...
uniapp日期区间选择器
uniapp日期区间选择器 在 uniapp 中创建一个简单的自定义日期范围的日期区间选择器: - 限制有效日期范围开始日期为 2024-01-01,结束日期为当日; - 默认日期区间为当日向前计算的7日区间; - 选择开始时间后,判断不可大…...
k8s job
ReplicaSet 和 DaemonSet 会持续运行任务,永远达不到完成态。但在一个可完成的任务中,其进程终止后,不应该再重新启动。 Job 允许你运行一种 pod,该 pod 在内部进程成功结束时,不重启容器,一旦任务完成&…...
Python---NumPy万字总结【此篇文章内容难度较大,线性代数模块】(3)
NumPy的应用(3) 向量 向量(vector)也叫矢量,是一个同时具有大小和方向,且满足平行四边形法则的几何对象。与向量相对的概念叫标量或数量,标量只有大小,绝大多数情况下没有方向。我们…...
【面试经典题】环形链表
个人主页:一代… 个人专栏:数据结构 在面试中我们经常会遇到有关链表的相关题目,面试官通常会对题目给出拓展 下面我就两个leetcode上的一个双指针的题目为例,并对其进行拓展 题目链接:环形链表 题目描述…...
【联合索引】最左匹配原则是什么?
什么是联合索引 联合索引(Composite Index)是一种索引类型,它由多个列组成。 MySQL的联合索引(也称为复合索引)是建立在多个字段上的索引。这种索引类型允许数据库在查询时同时考虑多个列的值,从而提高查询…...
LeetCode 700.二叉搜索树中的搜索
LeetCode 700.二叉搜索树中的搜索 1、题目 题目链接:700. 二叉搜索树中的搜索 给定二叉搜索树(BST)的根节点 root 和一个整数值 val。 你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则…...
程序设计实践-课程设计任务布置(麦当劳) (price 200)(不包含文档)
WX: help-assignment code price 200(不包含文档!不包含文档!不包含文档!) 课题任务-概述 2023年5月,麦当劳在北邮开业。大量的学生去那里订餐。正因为如此,麦当劳的在线点餐系统经常关闭以避…...
leetcode 918.环形子数组的最大和
思路:DP 其实和昨天做的哪个重复数组差不多,按顺序来说先做这个题目其实更好。 这里需要分两种情况:第一个,就是数组不越界的时候,这个时候最大子数组和就是leetcode 53题的题解。 如果说越界了,我们还需…...
Spring中用到的设计模式有哪些
工厂模式,BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象。 单例模式,Spring依赖注入Bean实例默认是单例的。Spring依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创…...
CSS 样式清单整理:文字超出部分显示省略号和设置placeholder的字体样式
单行文本的溢出显示省略号(一定要有宽度) p{width:200rpx;overflow: hidden;text-overflow:ellipsis;white-space: nowrap;}多行文本溢出显示省略号 p {display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 3;overflow: hidden;}设…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
