news 2026/8/23 13:55:46

单链表专题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单链表专题

前言

顺序表和单链表都是两种常见的数据结构,他们的区别究竟在哪里?

顺序表:顺序表是一种连续的存储结构,数据元素在内存中占据一块连续的空间。因为连续空间存储的特性,顺序表可以直接通过下表遍历元素。

单链表:单链表是一种离散的存储结构,数据元素存储在节点中,节点中包含数据和下一节点的指针。

总结:顺序表和单链表的区别在于他们的存储方式不同,顺序表是连续存储,单链表则是离散存储,单链表相对于顺序表的优势是,单链表可以降低操作时的时间复杂度。

1.链表的概念及结构

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序使通过链表中的指针链接次序实现的。

链表的结构就像这个小火车,每一个车厢就是一个节点,节点包括数据(车厢里的货物)和下一个节点的指针(车厢之间的抓钩)。

在链表中的小火车就像这样

每个节点对应的结构体代码就可以这样写出(假设当前保存的节点为整型)

typedef struct SListNode { int data; //节点数据 struct SListNode* next; //指针变量 用来保存下一个节点的地址 }SLTNode;
我们想要保存⼀个数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存数
据,也需要保存下⼀个节点的地址(当下⼀个节点为空时保存的地址为空)。
当我们想要从第⼀个节点⾛到最后⼀个节点时,只需要在前⼀个节点拿上下⼀个节点的地址就可以了。
那在链表结构中,如何实现节点从头到尾的打印?
void SLTPrint(SLTNode* phead){ SLTNode *pcur = phead; while(pcur) { printf("%d ",pcur->data); pcur = pcur->next; } printf("\n"); }

测试样例:

void SlistTest01(){ SLTNode* node1 = (SLTNode* )malloc(sizeof(SLTNode)); node1->data = 1; SLTNode* node2 = (SLTNode* )malloc(sizeof(SLTNode)); node1->data = 2; SLTNode* node3 = (SLTNode* )malloc(sizeof(SLTNode)); node1->data = 3; SLTNode* node4 = (SLTNode* )malloc(sizeof(SLTNode)); node1->data = 4; //此时创建好了节点数据 但还没有实现节点链接 node1-> = node2; node2-> = node3; node3-> = node4; node4-> = NULL; } void SLTPrint(SLTNode* phead){ SLTNode *pcur = phead; while(pcur) { printf("%d ",pcur->data); pcur = pcur->next; } printf("NULL\n"); } SLTNode* plist = node1; SLtPrint(plist);

测试结果

2.单链表的实现

2.1单链表的尾插

typedef char SLTDataType; SLTNode* SLTBuyNode(SLTDataType x) { SLTNode* newnode = (SLTNode* )malloc(sizeof(SLTNode)); if(newnode == NULL) { perror("malloc fail!"); exit(1); } newnode->data = x; newnode->next = NULL; return newnode; } void SLTPushBack(SLTNode** pphead,SLTDataType x){ assert(pphead); SLTNode* newnode = SLTBuyNode(x); //链表为空 新节点为phead if(*pphead == NULL) { *pphead = newnode; return; } //链表不为空 找尾结点 //为了不改变头结点 设置临时结构体变量 SLTNode* ptail = *pphead; while(ptail->next) { ptail = ptail->next; } //ptail就是尾结点 ptail->next = newnode; }

测试样例:

void SlistTest02() { SLTnode* plist = NULL; SLTPushback(&plist,1); SLTPushback(&plist,2); SLTPushback(&plist,3); SLTPushback(&plist,4); SLTPrint(plist); //结果 1->2->3->4->NULL }

运行结果

2.2单链表的头插

void SLTPushFront(SLTNode** pphead,SLTDataType x) { assert(pphead); SLTNode* newnode = SLTBuyNode(x); new->next=*pphead; *pphead = newnode; }

测试样例

void SlistTest03(){ SLTPushFront(&plist,5); SLTPrint(plist); SLTPushFront(&plist,6); SLTPrint(plist); SLTPushFront(&plist,7); SLTPrint(plist); }

结果

7->6->5->NULL

2.3 链表的头删和尾删

//单链表的尾删 void SLTPopBack(SLTNode** pphead){ assert(pphead); //pphead链表不能为空 *phead首节点也不能为空 assert(*pphead); //链表不为空 //链表只有一个节点,有多个节点 if((*pphead)->next == NULL) { free(*pphead); *pphead = NULL; return; } SLTNode* ptail = *pphead; SLTNode* prev = NULL; //存放前区节点 while(ptail->next) { prev = ptail; ptail = ptail->next; } prev->next = NULL; //销毁尾结点 free(ptail); ptail = NULL; } //单链表的头删 void SLTPopFront(SLTNode** pphead) { assert(pphead); assert(*pphead); //链表不能为空 //让第二个节点成为新的头 同时把旧的头结点释放掉 SLTNode* next = (*pphead)->next; free(*pphead); *pphead = next; } //测试 SLTPopBack(&plist); SLTPrint(plist); SLTPopFront(&plist); SLTPrint(plist);

2.4 链表的查找

SLTNode* SLTFind(SLTNode** pphead,SLTDataType x) { assert(pphead); //遍历链表 SLTNode* pcur = *pphead; while(pcur) //等价于pcur != NULL { if(pcur->data == x){ return pcur;} } //没有找到 return NULL; } //测试 SLTNode* FindRet = SLTFind(&plist); if(FindRet) { printf("找到了!"); } else{ printf("未找到!"); }

2.5 在指定位置之前插入数据

void SLTInsert(SLTNode** pphead,SLTNode* pos,SLTDataType x){ assert(pphead); assert(pos); assert(*pphead); //链表也不能为空 因为传入的指定节点也不能为空 SLTNode* newnode = SLTBuyNode(x); //当pos刚好是头结点时 if(pos == *pphead) { SLTPushFront(pphead,x);/头插 return; } //以下为pos不是头结点的情况 SLTNode* prev = *pphead; while(prev->next!=pos) { prev = prev->next; } } //测试 SLTNode* FindRet = SLTFind(&plist,4); SLTInsert(&plist,FindRet,100); SLTPrint(plist);

2.6 在指定位置之后插入数据

void SLTInsertAfter(SLTNode* pos,SLTDataType x) { assert(pos); //传入节点不能为空 SLTNode* newnode = SLTBuyNode(x); //创建新节点 newnode->next = pos->next; //先接新节点后 再接新节点前 pos->next = newnode; } //测试 void SlistTest03(){ SLTNode* plist = NULL; SLTPushBack(&plist,1); SLTPushBack(&plist,2); SLTPushBack(&plist,3); SLTPushBack(&plist,4); SLTPrint(plist); //1->2->3->4->NULL SLTNode* FindRet = SLTFind(&plist,1); SLTInsertAfter(FindRet,100); SLTPrint(plist); //1->100->2->3->4->NULL }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 13:52:02

从awesome-python3-webapp到iOS App:跨平台开发实战经验完整指南

从awesome-python3-webapp到iOS App:跨平台开发实战经验完整指南 【免费下载链接】awesome-python3-webapp 小白的Python入门教程实战篇 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-python3-webapp awesome-python3-webapp 是一个面向小白的 Pyth…

作者头像 李华
网站建设 2026/8/23 13:49:23

Xplorer文件管理器完全上手指南:跨平台文件管理一次搞定

Xplorer文件管理器完全上手指南:跨平台文件管理一次搞定 【免费下载链接】xplorer Xplorer, a customizable, modern file manager 项目地址: https://gitcode.com/gh_mirrors/xp/xplorer Xplorer文件管理器是一款免费开源的跨平台文件管理器,Win…

作者头像 李华
网站建设 2026/8/23 13:39:37

orga分词器源码剖析:基于text-kit读取器的lexer逐行设计解读

orga分词器源码剖析:基于text-kit读取器的lexer逐行设计解读 【免费下载链接】orgajs parse org-mode content into AST 项目地址: https://gitcode.com/gh_mirrors/or/orgajs orga 是 orgajs 中解析 org-mode 文本的核心包,它的分词器&#xff0…

作者头像 李华