本文主要是介绍单链表的增删查改的讲解与实现(一篇包懂),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一:顺序表的概念
二:顺序表的实现
第一点:
本文采用三个文件进行实现
1:SList.h(对实现函数以及节点的声明)
2:SList.c(增删查改的函数的实现)
3:text.c(对程序的使用检测)
第二点:
本文需要用到的参数和变量
1:plist:实参,头指针
2:phead:形参,头指针
3:pphead:实参的地址,二级指针
第三点:
所有的函数实现内部第一步永远考虑是否需要对接收到的结构体指针进行断言,这样会更严谨!
1:参数为pphead的,一定需要断言,因为不管头指针plist是否为空,头指针plist的地址(pphead)都不会为空!
2:*pphead(plist)在某些函数下需要进行断言!头插尾插检查pphead,头删尾删不仅需要检查pphead还要检查*pphead,因为如果plist(*pphead)为空,代表是个空链表,空链表无法进行头删和尾删!
三:函数的实现讲解
前提:节点的声明
解释:
1:data用来保存节点的值,next用来指向下一个节点
2:将类型进行一个typedef,方便之后的类型改变带来的修改,只需要修改int即可。
3:将结构体重命名为SLTNode,方便之后使用。
第一个函数:创建新节点函数
解释:
1:参数为一个值,将会赋给创建的新节点的data。然后将创建的节点的next置空(会方便后续的操作)。
2:初始化(malloc)顺序表的空间为一个节点的大小,malloc函数的返回值为void*,所以需要强转为SLTNode* 的类型,然后该空间才能给新节点使用。
3:malloc开辟失败的检测,以及exit(-1)代表即刻退出。
第二个函数:头插
解释:
1:头插一定会改变头指针的指向,本质是要改变plist指针的指向,所以参数应该是二级指针参数pphead(plist的地址),这样才能真正的改变plist指针。
2:对pphead断言,因为不管头指针plist是否为空,头指针plist的地址(pphead)都不会为空!不需要对*pphead(plist)断言,因为空链表也可以进行头插!
3:创建的newnode节点需要指向一开始头指针指向的节点(不管这个节点是NULL还是真的存在),然后再让头指针指向newnode节点。一定要注意这两步的先后顺序!
第三个函数:尾插
解释:
1:尾插有可能会成为头插,在该链表为空链表的时候,而头插会改变头指针(plist)的指向,所以参数也是一个二级指针(pphead)。
2:不需要对*pphead(plist)进行断言,因为链表为空也可以进行尾插。
3:情况1(空链表),只需要把头指针plist(*pphead)的指向改为尾插创建的newnode节点,newnode的next不需要置空,因为在节点创建函数里面,newnode的next就已经置空为NULL了。
4:情况2(不是空链表),那就需要找到尾节点,然后将尾节点指向newnode,while(tail->next!=NULL),这一步会让tail在指向尾节点的时候停下来,因为尾节点的next为NULL。
第四个函数:头删
解释:
1:头删不仅要对pphead进行断言检查,还要对*pphead进行检查,因为空链表无法头删。
2:头删就是让头指针去指向原本头指针指向节点的下一个节点,然后再去释放掉第一个节点的内容,而为什么不直接用*pphead(plist)去进行操作,因为这样释放的时候会释放掉操作后头指针指向的第二个节点,所以需要将头指针保存到新变量newhead中,这样才能完美的完成操作!
第五个函数:尾删
解释:
1:尾删不仅要对pphead进行断言检查,还要对*pphead进行检查,因为空链表无法尾删。
2:情况1(只有一个节点),该情况类似头删中只有一个节点的时候,只需要将*ppead(plist)指向的内容free掉,然后将*pphead的next置空。
3:情况2(不止一个节点)
方法一:创建两个变量,tail和tailprev,目的是最后让tail指向尾节点,while(tail->next!=NULL),这一步会让tail在指向尾节点的时候停下来,因为尾节点的next为NULL。让tailprev指向倒数第二个节点(尾节点的前一个节点),然后释放掉tail指向的尾节点,然后把tail置空,最后把tailprev(指向倒数第二个节点)的next置空,因为此时倒数第二个节点就是尾节点了,尾节点的next应该为NULL。
方法二:只需要创建一个变量tail就行,while(tail->next->next)这一步会让tail最后指向倒数第二个节点,然后再tail->next找到尾节点,将其释放,然后再把tail 的next置空。
第六个函数:查找是否存在某节点的值为x
解释:
1:不需要断言,因为空链表我们找不到会返回NULL
2:找到会返回cur指向的节点
第七个函数:在pos节点之前插入一个值为x的节点
解释:
1:不仅要对pphead进行断言检查,还要对*pphead进行检查,因为空链表无法找到pos节点。
2:情况1(头插),在第一个节点前插入,复用头插函数即可。
3:情况2(其他位置插入),创建一个prev,去找到pos节点的前一个节点,然后把prev指向插入的新节点newnode,然后再让newnode指向pos节点,这两步的先后顺序很重要!
第八个函数:在pos节点之后插入一个值为x的节点
解释:
1:对pos的断言,因为无法寻找空节点。
2:先让插入的新节点指向原先pos指向的节点,然后再让pos去指向这个新节点,这两步的先后顺序很重要!
第九个函数:删除pos节点
解释:
1:不仅要对pphead断言检查,也要对pos断言检查,因为无法删除一个空节点。
2:情况1(头删),删除第一个节点的时候,直接复用头删函数即可。
3:情况2(删除其他位置节点,包括尾删),创建一个prev,while循环让prev指向pos的前一个节点,然后将prev指向pos指向的节点,最后再释放掉pos节点。
第十个函数:删除pos节点的后一个节点
解释:
1:不仅要对pos断言检查,因为无法删除空节点的下一个节点,也要对pos的下一个节点(pos->next)进行断言检查,因为如果下一个节点为空,也无法删除。
2:创建一个posNext,让其指向pos的下一个节点,然后让pos指向下一个节点(posNext)的下一个节点,最后再去释放(posNext),并将其置空。
第十一个函数:打印单链表
解释:
1:不需要断言,空链表本身就是NULL。
2:遍历打印
最后是text.c函数进行一系列测试的运行结果:
效果如下:
头文件的展示:
这篇关于单链表的增删查改的讲解与实现(一篇包懂)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!