当前位置: 首页 > article >正文

C语言数据结构2-单向链表实现

数据结构链表链表是数据结构中最常用的线性结构许多非线性结构也都是链表节点魔改后形成的非链式结构。链表的分类按有无头节点分不含头节点的链表这种链表存在操作不统一的问题操作第一个节点和后面的第i个节点代码不同代码简洁性不佳含有头节点的链表操作统一易于编码按链表结构分单向链表每个节点只有一个指针指向自己的后继双向链表每个节点有两个指针一个指向自己的前驱一个指向自己的后继循环链表尾节点指针指向头节点单向循环链表每个节点只有一个指针指向自己的后继双向循环链表每个节点有两个指针一个指向自己的前驱一个指向自己的特殊操作链表栈像弹夹先压入的子弹元素后射出出栈队列像水管先进入队列的元素先出队列一般队列队列一侧只能插入另一侧只能弹出双向队列两侧都可以插入或者删除单向链表的定义与功能声明头文件如下typedef int E;// 对节点内数据起别名如果要其他类型可以修改 typedef struct LinkNode{ E element; // 链表节点元素 struct LinkNode * next; //指向自己后继的指针 }linkNode; typedef struct LinkNode * Node ;// 对链表指针起别名 ​ void InitLinkList(Node Head);// 对链表进行初始化定义头节点初始参数 _Bool insertLinkList(Node Head,E element,int index);//插入节点 _Bool deleteLinkList(Node Head,int index);//删除元素 E GetElementByIndex(Node Head,int index);//根据元素在链表中的位置获取节点的元素值 Node GetPointByElement(Node Head,E element);//根据元素取值寻找对应节点 void printLinkList(Node head);//打印整个链表 int GetLinkListSize(Node head);//获取链表长度(不包括头节点)功能函数初始化函数插入函数删除函数按索引获取节点元素值按元素值获取节点指针打印链表获取链表长度函数的具体实现函数初始化void InitLinkList(Node Head){ if(Head NULL){ printf([ERROR]:undefined LinkList\n ); return; }//判断是否传入无效地址 Head-next NULL;//将头节点指针置空 printf([LOG]:This new LinkList s Adress is %p\n,Head);//打印信息 }插入函数插入的核心就是找到待插入位置的前驱节点将待插入节点的后继置为当前该位置的地址将前驱节点的指针置为待插入节点的地址同时注意插入索引的合法性[1.size1 ]_Bool insertLinkList(Node Head,E element,int index){ if(HeadNULL){ printf([LOG]: undefined LinkList\n); return 0; }//判断传入指针是否为空指针 if(index1){ printf([ERROR]:Wrong index\n); return 0; }//判断插入位置合法性正常的插入位置是1~size1,也就是第一个位置头节点后的第一个到最后一个节点之后 while(--index){ if(Head-next NULL) return 0;//限制只能插入到最后一个节点的后面 Head Head-next;//移动指针 } Node node malloc(sizeof(struct LinkNode)); // malloc是给指针分配内存 node-element element;//给节点元素赋值 node-next Head-next;//修改待插入节点的后继指针为为当前指针的后继 Head-next node;//修改当前指针的后继为待插入节点 printf([LOG]:insert success\n[INFO]:Front Node address %p,Target Node address %p\n,Head,node);//打印信息 return 1; }删除函数删除的核心就是找到待插入位置的前驱节点先记录待删除节点的指针将前驱节点的后继置为待删除节点的后继最后释放待删除节点的内存空间_Bool deleteLinkList(Node Head,int index){ if(HeadNULL){ printf([ERROR]:undefined LinkList\n); return 0; }//判断指针是否为空 if(index1){ printf([ERROR]:Wrong index\n); return 0; }//判断插入位置合法性 Node DeleteNode;//设置指针变量准备记录待删除节点的指针 while(--index){ if(Head-next NULL){ printf([ERROR]:Wrong index\n); return 0; }//寻找待删除节点的前驱 Head Head-next;//移动指针位置 } DeleteNode Head-next;//记录待删除指针的地址 Head-next Head-next-next;//重置待删除节点的前驱节点的指针 printf([LOG]:Delete success,Node Adress %p,Node element %d\n ,DeleteNode,DeleteNode-element); free(DeleteNode);//释放节点的地址空间 return 1; }打印函数void printLinkList(Node head){ if(headNULL){ printf([ERROR]: undefined LinkList\n); return ; } while(head-next! NULL){ head head-next; printf([%d,%p]-,head-element,head-next); } return; }获取链表长度int GetLinkListSize(Node Head){ if(Head NULL){ printf([ERROR]:undefined LinkList\n); return 0; }//指针判空 int Size 0; while(Head-next){ Head Head-next; Size; }//遍历整个链表并更新size变量 return Size; }按位置查找E GetElementByIndex(Node Head,int index){ if(HeadNULL){ printf([ERROR]:undefined LinkList\n); return -1; }//指针判空 if(index1||indexGetLinkListSize(Head)){ printf([ERROR]:Wrong index\n); return -1; }//查找位置合法性判断 while(index--){ Head Head-next; }//移动指针 return Head-element;//返回对应索引的元素 }按值查找节点Node GetPointByElement(Node Head,E element){ if(HeadNULL){ printf([ERROR]:undefined LinkList\n); return NULL; }//指针判空 while(Head-next!NULL){ Head Head-next;//移动指针 if(Head-element element){//和每个节点的元素做匹配 printf([LOG]:Find success\n[INFO]: Node Address %p,Node element %d\n,Head,Head-element); return Head;//找到立刻返回 } } printf([LOG]:this element not in the LinkList\n); return NULL; }功能测试测试代码#include stdio.h #include stdlib.h #include LinkNode.h int main() { printf( 链表完整功能测试 \n\n); ​ // 创建头结点 linkNode Head; Node head Head; InitLinkList(head); ​ printf(\n 1. 插入测试 \n); ​ printf(\n--- 在位置1插入10 ---\n); insertLinkList(head, 10, 1); printLinkList(head); ​ printf(\n--- 在位置2插入20 ---\n); insertLinkList(head, 20, 2); printLinkList(head); ​ printf(\n--- 在位置2插入30 ---\n); insertLinkList(head, 30, 2); printLinkList(head); ​ printf(\n--- 在位置1插入5 ---\n); insertLinkList(head, 5, 1); printLinkList(head); ​ printf(\n--- 在位置4插入25 ---\n); insertLinkList(head, 25, 4); printLinkList(head); ​ printf(\n--- 在位置1插入100 ---\n); insertLinkList(head, 100, 1); printLinkList(head); ​ printf(\n 2. 获取大小 \n); int size GetLinkListSize(head); printf(当前链表大小: %d\n, size); ​ printf(\n 3. 按索引获取元素 \n); for(int i 1; i size; i) { E elem GetElementByIndex(head, i); printf(位置 %d 的元素: %d\n, i, elem); } ​ printf(\n--- 测试无效索引 ---\n); printf(位置0: %d\n, GetElementByIndex(head, 0)); printf(位置100: %d\n, GetElementByIndex(head, 100)); ​ printf(\n 4. 按元素获取节点指针 \n); ​ printf(\n--- 查找存在的元素25 ---\n); Node p GetPointByElement(head, 25); if(p ! NULL) { printf(找到节点值为: %d\n, p-element); } ​ printf(\n--- 查找存在的元素5 ---\n); p GetPointByElement(head, 5); if(p ! NULL) { printf(找到节点值为: %d\n, p-element); } ​ printf(\n--- 查找不存在的元素999 ---\n); p GetPointByElement(head, 999); if(p NULL) { printf(未找到节点\n); } ​ printf(\n 5. 删除测试 \n); ​ printf(\n--- 删除位置3 ---\n); deleteLinkList(head, 3); printLinkList(head); ​ printf(\n--- 删除位置1 ---\n); deleteLinkList(head, 1); printLinkList(head); ​ printf(\n--- 删除最后位置 ---\n); int currentSize GetLinkListSize(head); deleteLinkList(head, currentSize); printLinkList(head); ​ printf(\n--- 删除位置2 ---\n); deleteLinkList(head, 2); printLinkList(head); ​ printf(\n--- 测试无效删除 ---\n); deleteLinkList(head, 0); deleteLinkList(head, 10); printLinkList(head); ​ printf(\n 6. 边界测试 \n); printf(当前链表: ); printLinkList(head); printf(当前大小: %d\n, GetLinkListSize(head)); ​ printf(\n--- 向空链表插入测试 ---\n); linkNode EmptyHead; Node emptyHead EmptyHead; InitLinkList(emptyHead); printf(空链表大小: %d\n, GetLinkListSize(emptyHead)); printf(插入元素999到位置1:\n); insertLinkList(emptyHead, 999, 1); printLinkList(emptyHead); ​ printf(\n--- 从单节点链表删除 ---\n); deleteLinkList(emptyHead, 1); printLinkList(emptyHead); ​ printf(\n 7. 压力测试 \n); linkNode StressHead; Node stressHead StressHead; InitLinkList(stressHead); ​ printf(\n--- 插入100个元素 ---\n); for(int i 1; i 100; i) { insertLinkList(stressHead, i*10, i); if(i % 20 0) { printf(已插入 %d 个元素, 当前大小: %d\n, i, GetLinkListSize(stressHead)); } } ​ printf(\n--- 删除50个元素 (每隔一个删一个) ---\n); for(int i 1; i 50; i) { deleteLinkList(stressHead, i); if(i % 10 0) { printf(已删除 %d 个元素, 当前大小: %d\n, i, GetLinkListSize(stressHead)); } } ​ printf(\n最终压力测试链表: ); printLinkList(stressHead); printf(最终大小: %d\n, GetLinkListSize(stressHead)); ​ printf(\n 8. GetPointByElement 综合测试 \n); linkNode TestHead; Node testHead TestHead; InitLinkList(testHead); ​ // 插入测试数据 insertLinkList(testHead, 11, 1); insertLinkList(testHead, 22, 2); insertLinkList(testHead, 33, 3); insertLinkList(testHead, 44, 4); insertLinkList(testHead, 55, 5); ​ printf(测试链表: ); printLinkList(testHead); ​ printf(\n--- 查找头部元素11 ---\n); Node found GetPointByElement(testHead, 11); if(found) printf(找到: %d at %p\n, found-element, found); ​ printf(\n--- 查找中间元素33 ---\n); found GetPointByElement(testHead, 33); if(found) printf(找到: %d at %p\n, found-element, found); ​ printf(\n--- 查找尾部元素55 ---\n); found GetPointByElement(testHead, 55); if(found) printf(找到: %d at %p\n, found-element, found); ​ printf(\n--- 查找不存在的元素100 ---\n); found GetPointByElement(testHead, 100); if(!found) printf(正确返回NULL\n); ​ printf(\n 9. 综合操作测试 \n); linkNode FinalHead; Node finalHead FinalHead; InitLinkList(finalHead); ​ // 混合操作 printf(\n初始插入: ); insertLinkList(finalHead, 1, 1); insertLinkList(finalHead, 3, 2); insertLinkList(finalHead, 5, 3); printLinkList(finalHead); ​ printf(在位置2插入2: ); insertLinkList(finalHead, 2, 2); printLinkList(finalHead); ​ printf(在位置4插入4: ); insertLinkList(finalHead, 4, 4); printLinkList(finalHead); ​ printf(删除位置3: ); deleteLinkList(finalHead, 3); printLinkList(finalHead); ​ printf(查找元素4: ); Node foundNode GetPointByElement(finalHead, 4); if(foundNode) printf(找到元素4地址: %p\n, foundNode); ​ printf(最终结果: ); for(int i 1; i GetLinkListSize(finalHead); i) { printf(%d , GetElementByIndex(finalHead, i)); } printf(\n); ​ printf(\n 所有测试完成 \n); ​ return 0; ​ }测试结果 9. 综合操作测试 [LOG]:This new LinkList s Adress is 00000044363FF940 ​ 初始插入: [LOG]:insert success [INFO]:Front Node address 00000044363FF940,Target Node address 00000221D6390F20 [LOG]:insert success [INFO]:Front Node address 00000221D6390F20,Target Node address 00000221D6391060 [LOG]:insert success [INFO]:Front Node address 00000221D6391060,Target Node address 00000221D63911A0 [1,00000221D6391060]-[3,00000221D63911A0]-[5,0000000000000000]-在位置2插入2: [LOG]:insert success [INFO]:Front Node address 00000221D6390F20,Target Node address 00000221D6390E20 [1,00000221D6390E20]-[2,00000221D6391060]-[3,00000221D63911A0]-[5,0000000000000000]-在位置4插入4: [LOG]:insert success [INFO]:Front Node address 00000221D6391060,Target Node address 00000221D6391240 [1,00000221D6390E20]-[2,00000221D6391060]-[3,00000221D6391240]-[4,00000221D63911A0]-[5,0000000000000000]-删除位置3: [LOG]:Delete success,Node Adress 00000221D6391060,Node element 3 [1,00000221D6390E20]-[2,00000221D6391240]-[4,00000221D63911A0]-[5,0000000000000000]-查找元素4: [LOG]:Find success [INFO]: Node Address 00000221D6391240,Node element 4 找到元素4地址: 00000221D6391240 最终结果: 1 2 4 5 ​ 所有测试完成

相关文章:

C语言数据结构2-单向链表实现

数据结构链表链表是数据结构中最常用的线性结构,许多非线性结构也都是链表节点魔改后形成的非链式结构。链表的分类按有无头节点分不含头节点的链表:这种链表存在操作不统一的问题,操作第一个节点和后面的第i个节点代码不同,代码简…...

Confluence数据迁移实战:从本地备份到云服务器恢复的完整避坑指南

Confluence数据迁移实战:从本地到云的完整避坑指南 当企业决定将Confluence从本地服务器迁移到云平台时,技术团队往往面临一系列隐藏的挑战。不同于简单的备份恢复,跨环境迁移涉及操作系统差异、网络配置、权限体系重构等复杂问题。我曾主导过…...

Python 3.12 升级后 pip 罢工?一招教你用 ensurepip 修复 pkgutil 报错

Python 3.12 升级后 pip 罢工?一招教你用 ensurepip 修复 pkgutil 报错 最近不少开发者将 Python 升级到 3.12 版本后,遇到了一个令人头疼的问题:原本运行良好的 pip 命令突然报错,提示 module pkgutil has no attribute ImpImpo…...

5分钟快速配置:让Mem Reduct内存管理工具完美适配你的使用习惯

5分钟快速配置:让Mem Reduct内存管理工具完美适配你的使用习惯 【免费下载链接】memreduct Lightweight real-time memory management application to monitor and clean system memory on your computer. 项目地址: https://gitcode.com/gh_mirrors/me/memreduct…...

从URDF到SDF:搞机器人仿真,你该用哪个模型文件?一篇讲清区别和选择

URDF与SDF深度对比:机器人仿真模型选型实战指南 当你在深夜调试机器人仿真时,是否经历过这样的场景:URDF文件在Rviz中运行完美,但导入Gazebo后关节却像断了线的木偶般瘫软无力?或是面对并联机器人复杂的封闭链结构&…...

告别混乱!用ElementUI DatePicker构建清晰易用的Vue表单:类型选择、值绑定与格式化避坑指南

告别混乱!用ElementUI DatePicker构建清晰易用的Vue表单:类型选择、值绑定与格式化避坑指南 在构建活动发布、订单管理等包含复杂表单的Vue项目时,日期时间选择往往是开发者最容易踩坑的环节之一。ElementUI的DatePicker组件虽然功能强大&…...

B站视频下载终极指南:5分钟掌握免费下载大会员4K高清内容

B站视频下载终极指南:5分钟掌握免费下载大会员4K高清内容 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 还在为无法离线观…...

搞GIS开发必懂:CGCS2000、西安80、北京54,这些国家坐标系到底该怎么选?

GIS开发实战:国家坐标系选型与数据转换全指南 当你打开一份十年前的CAD地形图,或是接手一个跨区域的地理信息项目时,坐标系问题往往会成为第一个拦路虎。那些标注着BJ54、XIAN80的老旧数据,与现在主流的CGCS2000标准格格不入&…...

如何用HTML转Figma工具实现高效设计逆向工程:完整实战指南

如何用HTML转Figma工具实现高效设计逆向工程:完整实战指南 【免费下载链接】figma-html Convert any website to editable Figma designs 项目地址: https://gitcode.com/gh_mirrors/fi/figma-html HTML转Figma工具是一个开源的Chrome扩展,能够将…...

Tidyverse 2.0报告自动化上线倒计时:3个未公开的breaking change正在 silently break你的旧pipeline(附迁移checklist v2.0.3)

更多请点击: https://intelliparadigm.com 第一章:Tidyverse 2.0报告自动化上线倒计时全景概览 Tidyverse 2.0 正式版已进入发布前最后验证阶段,核心目标是将数据清洗、可视化与报告生成深度整合为端到端自动化流水线。本次升级不再仅限于包…...

AD9371官方例程NO-OS调试笔记:从SYSREF脉冲到链路同步,手把手排查JESD204B初始化问题

AD9371 JESD204B链路同步实战:从SYSREF异常到确定性延迟的深度排错指南 当你在ZCU106开发板上调试AD9371时,是否遇到过这样的场景:按照官方手册配置完所有参数后,JESD204B链路始终无法建立同步?或者更令人抓狂的是——…...

别再乱抄代码了!WPF整合MaterialDesign与MahApps.Metro的完整资源字典配置指南

WPF双UI框架整合实战:MaterialDesign与MahApps.Metro资源字典配置全解析 当现代WPF应用需要同时呈现Material Design的精致质感与Metro风格的流畅界面时,开发者往往会陷入资源冲突的泥潭。本文将彻底解决这个痛点——通过深度拆解资源加载机制&#xff0…...

高效定制你的《边缘世界》开局:EdB Prepare Carefully模组实用指南

高效定制你的《边缘世界》开局:EdB Prepare Carefully模组实用指南 【免费下载链接】EdBPrepareCarefully EdB Prepare Carefully, a RimWorld mod 项目地址: https://gitcode.com/gh_mirrors/ed/EdBPrepareCarefully 你是否厌倦了《边缘世界》中随机生成的殖…...

从‘愣头青’到‘心里有谱’:我的第一块高速PCB板SI仿真复盘(附Sigplorer卡死解决方案)

从‘愣头青’到‘心里有谱’:我的第一块高速PCB板SI仿真复盘 第一次接触高速PCB设计时,我像个拿着地图却看不懂方向的旅人。原厂的参考设计就像那张地图,让我误以为只要按图索骥就能到达终点。直到测试结果与预期相差甚远,我才明白…...

智能座舱ICC控制器实战:手把手教你用SR场景重构和2秒校验机制优化HMI体验

智能座舱ICC控制器实战:SR场景重构与2秒校验机制的工程实现 在智能座舱的开发中,ICC控制器作为人机交互的核心枢纽,其稳定性和响应速度直接决定了用户体验。本文将深入探讨两个关键模块的实现细节:SR场景重构中的车道线系数跳变处…...

Unity Shader实战:5分钟搞定物体轮廓外发光,附完整代码与避坑指南

Unity Shader实战:5分钟实现高级轮廓外发光效果 在游戏开发中,物体高亮效果是提升交互体验的关键细节。想象一下,当玩家选中角色、拾取道具或触发关键UI时,一个醒目的发光轮廓能瞬间吸引注意力——这种看似简单的效果,…...

主动收入 = 被动收入?

这是一个典型的**“现金流性质混淆”。虽然它们最终都进入你的银行账户,但它们的生成机制、边际成本、可扩展性 (Scalability)** 和 风险结构 截然不同。 如果把财富积累比作开一家软件公司: 主动收入 (Active Income):是写代码 (Coding)。…...

ARM开发板Qt5.15.2环境升级记:手把手教你编译安装qtvirtualkeyboard与svg依赖库

ARM开发板Qt5.15.2环境升级:编译安装qtvirtualkeyboard与svg依赖库全指南 在嵌入式开发中,虚拟键盘功能往往是用户交互的关键组件。当你的ARM开发板已经预装了Qt5.15.2基础环境,却发现缺少这一核心功能时,手动添加qtvirtualkeyboa…...

别只盯着Prometheus了!Zabbix 6.0 LTS监控K8s集群的保姆级避坑指南

别只盯着Prometheus了!Zabbix 6.0 LTS监控K8s集群的保姆级避坑指南 在Kubernetes监控领域,Prometheus似乎已经成为默认选择,但这是否意味着它是唯一可行的方案?对于那些已经在传统IT架构中深度使用Zabbix的团队来说,切…...

深度睡眠的本质的庖丁解牛

它的本质是:在睡眠周期中,脑电波频率降至最低(0.5-4 Hz Delta 波),意识完全断连,身体进入“低功耗、高修复”模式。这是大脑进行 类淋巴系统清洗 (Glymphatic Clearance)、突触稳态重置 (Synaptic Homeosta…...

英雄联盟玩家必备:League Akari 本地化效率工具完全指南

英雄联盟玩家必备:League Akari 本地化效率工具完全指南 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 在英雄联盟的竞技对局中&a…...

通过Taotoken CLI工具一键生成Java项目所需的环境配置

通过Taotoken CLI工具一键生成Java项目所需的环境配置 1. 准备工作 在开始使用Taotoken CLI工具配置Java项目环境之前,需要确保您的开发环境已经安装了Node.js运行环境。Node.js是运行Taotoken CLI工具的基础依赖,您可以从Node.js官方网站下载并安装适…...

长期使用Taotoken服务感受到的API调用稳定性与技术支持响应

长期使用Taotoken服务感受到的API调用稳定性与技术支持响应 1. 视频生产场景下的稳定性表现 在过去六个月的视频项目制作周期中,我们团队持续通过Taotoken平台调用多种大模型API完成脚本生成、字幕优化和创意建议等任务。在日均300-500次调用的压力下,…...

从图像滤镜到推荐算法:Hadamard积和Kronecker积在AI项目里的‘隐藏’用法与性能调优

从图像滤镜到推荐算法:Hadamard积和Kronecker积在AI项目里的‘隐藏’用法与性能调优 当你在Instagram上滑动滤镜,或是在Netflix看到"猜你喜欢"的推荐时,可能不会想到背后藏着两个强大的数学工具——Hadamard积和Kronecker积。这两种…...

告别‘一病一药’:用PromptIR这个‘万能提示’模块,一个模型搞定图片去雾、去雨、去噪

万能提示模块PromptIR:用单一模型解决复杂图像恢复难题 监控摄像头在暴雨中失效、历史照片布满噪点、雾霾笼罩的风景照失去细节——这些图像退化问题困扰着无数开发者和终端用户。传统解决方案需要为每种退化类型单独训练模型,就像医院为每种疾病开发专用…...

为团队统一配置 Taotoken CLI 工具提升开发效率

为团队统一配置 Taotoken CLI 工具提升开发效率 1. 团队协作中的模型调用痛点 在技术团队协作开发过程中,大模型调用环境的配置往往成为效率瓶颈。每位开发者需要单独处理API密钥管理、模型选择、Base URL设置等重复性工作,不仅耗时且容易出错。当团队…...

企业文档格式转换的智能化解决方案:从语雀Lake到Markdown的知识资产迁移

企业文档格式转换的智能化解决方案:从语雀Lake到Markdown的知识资产迁移 【免费下载链接】YuqueExportToMarkdown 将语雀导出的lake文件转为markdown 项目地址: https://gitcode.com/gh_mirrors/yu/YuqueExportToMarkdown 在数字化转型浪潮中,企业…...

OPERA解码策略:如何通过注意力惩罚机制缓解多模态大模型幻觉问题

1. 项目概述:解码幻觉,让多模态大模型“眼见为实”如果你最近玩过像 LLaVA、MiniGPT-4 这类多模态大语言模型,可能会遇到一个让人哭笑不得的场景:你给模型看一张“桌子上放着一个苹果”的图片,它却信誓旦旦地告诉你“盘…...

Synchronous Audio Router深度解析:Windows专业音频路由架构揭秘与实战指南

Synchronous Audio Router深度解析:Windows专业音频路由架构揭秘与实战指南 【免费下载链接】SynchronousAudioRouter Low latency application audio routing for Windows 项目地址: https://gitcode.com/gh_mirrors/sy/SynchronousAudioRouter Synchronous…...

MagicUI组件库:基于React与Tailwind CSS的魔法交互实现

1. 项目概述:从“魔法UI”说起,一个组件库的诞生与价值最近在逛一些前沿的设计与开发社区时,经常看到一个名字被反复提及:magicuidesign/magicui。乍一看,这个名字就很有意思,“Magic UI”,直译…...