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

news2026/5/1 18:25:55
数据结构链表链表是数据结构中最常用的线性结构许多非线性结构也都是链表节点魔改后形成的非链式结构。链表的分类按有无头节点分不含头节点的链表这种链表存在操作不统一的问题操作第一个节点和后面的第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 ​ 所有测试完成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2572722.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…