朝花夕拾 · 数据结构 | 链表篇
一.逻辑结构与存储结构1.数据的逻辑结构2.数据的存储结构顺序存储与链式存储的区别顺序存储1.需要占用内存相邻一块连续的空间若开辟空间较大时则可能挤占其余内存空间产生部分内存外部碎片。2.由于是顺序存储元素之间可连续读取适合查改效率高但不适合增删对顺序存储结构进行增删需遍历数组将部分元素进行移动。3.需要进行预分配内存由于先分配后使用所以申请空间可能大可能小造成内存浪费或数组越界。链式存储1.不要求逻辑上相邻的元素在物理上也相邻可借助元素的后继指针连接可以充分利用内存空间不会出现内存碎片现象。2.由于不要求物理上连续所以每个元素需要指针来指向后一个元素增加了内存的消耗。3.与顺序存储相反链式存储适合增删对于元素的位置只需修改前驱与后继的指针即可而不适合查改每次遍历都只能从头指针开始向后遍历整个链表也可采用双向链表或循环链表进行优化。4.不需要进行预分配内存每次使用时动态开辟空间即可即用即存不需要时可及时释放内存空间。注意线性表是一种逻辑结构表示元素之间一对一的相邻关系。顺序表和链表是指存储结构两者属于不同层面的概念因此不要将其混淆。二.链表1.链表的定义线性表的链式存储也称单链表它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系对每个链表结点除存放元素自身的信息外还需要存放一个指向其后继的指针。单链表结点结构如图2.3所示其中data为数据域存放数据元素;next为指针域存放其后继结点的地址。typedef struct Node //定义结点结构 { int data; struct Node *pnext; }Node; typedef struct //定义链表结构 { int len; Node *phead; }Link;2.基本功能通常用头指针来标识一个单链表指出链表的起始地址头指针为NULL时表示一个空表。此外为了操作上的方便在单链表第一个数据结点之前附加一个结点称为头结点。头结点的数据域可以不设任何信息但也可以记录表长等信息。单链表带头结点时头指针指向头结点如图(a)所示。单链表不带头结点时头指针L指向第一个数据结点如图(b)所示。表尾结点的指针域为NULL(用“^”表示)。带头结点的链表代码操作较为简单且规范故推荐定义链表时采用带头结点的方式。以下有三种链表结构的创建与初始化无Link容器的带头结点Node * create_link() { Node *phead malloc(sizeof(Node)); if(NULLphead) { printf(malloc error\n); return NULL; } phead-pnextNULL; phead-data0; //头结点data为无效值 return phead; }Link容器的带头结点Link * create_link() { Link *plink malloc(sizeof(Link)); if(NULLplink) { printf(malloc error\n); return NULL; } Node *head malloc(sizeof(Node)); if(NULL head) { printf(mallochead error\n); return NULL; } head-data0; //头结点可不赋值 head-pnextNULL; plink-len0; plink-pheadhead; return plink; }Link容器的不带头结点Link *create_link() //不带头结点通过Link管理链表是否带头结点主要看链表有无空结点 { Link *plink malloc(sizeof(Link)); if (NULL plink) { printf(malloc error\n); return NULL; } plink-phead NULL; plink-len 0; return plink; }头结点和头指针的关系:不管带不带头结点头指针都始终指向链表的第一个结点而头结点是带头结点的链表中的第一个结点结点内通常不存储信息。引入头结点后可以带来两个优点:1.第一个数据结点的位置被存放在头结点的指针域中因此在链表的第一个位置上的操作和在表的其他位置上的操作一致无须进行特殊处理。2.无论链表是否为空其头指针都是指向头结点的非空指针(空表中头结点的指针域为空)因此空表和非空表的处理也就得到了统一。内存布局以下为三种常见链表结构以下为不带头结点的链表相关基础功能int insert_link_head(Link_t *plink, int data) //头插 { Node_t *pinsert malloc(sizeof(Node_t)); if (NULL pinsert) { printf(malloc error\n); return -1; } pinsert-data data; pinsert-pnext NULL; pinsert-pnext plink-phead; plink-phead pinsert; plink-clen; return 0; } void show_link(Link_t *plink) //遍历 { Node_t *ptmp plink-phead; while (ptmp ! NULL) { printf(%d , ptmp-data); ptmp ptmp-pnext; } printf(\n); } int is_empty_link(Link_t *plink) //判空 { if (NULL plink-phead) { return 1; } return 0; } int insert_link_tail(Link_t *plink, int data) //尾插 { Node_t *pinsert malloc(sizeof(Node_t)); if (NULL pinsert) { printf(mallocc error\n); return -1; } pinsert-data data; pinsert-pnext NULL; if (is_empty_link(plink)) { plink-phead pinsert; } else { Node_t *ptmp plink-phead; while (ptmp-pnext ! NULL) { ptmp ptmp-pnext; } ptmp-pnext pinsert; } plink-clen; return 0; }int delete_link_head(Link_t *plink) //头删 { if (is_empty_link(plink)) { return -1; } Node_t *pfree plink-phead; plink-phead pfree-pnext; free(pfree); plink-clen--; return 0; } int delete_link_tail(Link_t *plink) //尾删 { if (is_empty_link(plink)) { return -1; } else if (NULL plink-phead-pnext) { free(plink-phead); plink-phead NULL; } else { Node_t *ptmp plink-phead; while (ptmp-pnext-pnext ! NULL) { ptmp ptmp-pnext; } free(ptmp-pnext); ptmp-pnext NULL; } plink-clen--; return 0; } void destroy_link(Link_t *plink) //销毁 { while (!is_empty_link(plink)) { delete_link_head(plink); } free(plink); }3.内存泄漏内存泄露用户自己申请的堆区空间使用完没有及时释放则造成内存泄露。检测程序有没有内存泄露valgrind内存错误检测工具GNU提供可以检测程序运行过程中的内存泄露情况以及野指针的使用情况等。使用方法安装valgrind工具sudo apt-get isntall valgrind 编译完程序后使用 valgrind ./a.out valgrind --leak-checkfull ./a.out 6742 HEAP SUMMARY: 6742 in use at exit: 112 bytes in 7 blocks 6742 total heap usage: 10 allocs, 3 frees, 1,168 bytes allocated 6742 6742 LEAK SUMMARY: 6742 definitely lost: 16 bytes in 1 blocks 6742 indirectly lost: 96 bytes in 6 blocks 6742 possibly lost: 0 bytes in 0 blocks 6742 still reachable: 0 bytes in 0 blocks 6742 suppressed: 0 bytes in 0 blocks 6742 Rerun with --leak-checkfull to see details of leaked memory

相关新闻

C语言学习之数据结构 :基本概念

C语言学习之数据结构 :基本概念

数据结构 一 .基本概念 1.数据结构 数据结构:存储具有一种或或多种特定关系的数据的集合(如何组织和存储数据) 程序设计 数据结构 算法 2.数据与数据之间的关系 逻辑结构:数据元素与元素之间的关系 集合 :数据元素与…

2026/10/29 23:30:38 阅读更多 →
基于ROS2与MoveIt的宇树G1人形机器人传统舞蹈动作规划实战

基于ROS2与MoveIt的宇树G1人形机器人传统舞蹈动作规划实战

最近在探索人形机器人的应用边界时,一个有趣的想法冒了出来:能否让宇树G1这样先进的机器人,穿上传统服饰,演绎一段富有文化韵味的舞蹈?这不仅是技术上的挑战,更是艺术与科技融合的一次尝试。本文将完整分享…

2026/11/1 11:49:37 阅读更多 →
企业财务落地 AI Agent 如何选型?云上企业级 AI 助手与财务场景方案推荐 —— 优先从 Amazon Quick 及四条财务链路落地

企业财务落地 AI Agent 如何选型?云上企业级 AI 助手与财务场景方案推荐 —— 优先从 Amazon Quick 及四条财务链路落地

财务团队布局AI Agent智能化升级,可优先选用亚马逊云科技Amazon Quick。该平台是适配企业全员使用的企业级财务AI助手,依托Agent、Space、Research、Dashboard四大核心模块,可将日常凭证处理、资金经营分析、月末关账核对、合规合同审核等碎片…

2026/11/2 0:15:54 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/2 0:25:10 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/1 10:36:53 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/1 10:36:51 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/2 1:16:51 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/1 10:35:11 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/1 9:35:41 阅读更多 →

日新闻

周新闻

月新闻