8.修改:ListNodeModify
查找:ListNodeFind
对于修改和单链表一样需要先去查找,根据给出的数据返回的地址进行修改:
查找具体代码:
修改具体代码:
主函数里面的调用情况:
逻辑测试:
我们不妨就把数据1修改为数据100:
测试逻辑没问题
9.任意插入:ListNodeInsert
还记得对于单链表是怎样插入的吗?传了几个参数?当时我们传了3个参数:phead、pos、x;而对于双链表我们只需要传2个参数:pos、x;为什么呢?因为单链表传头结点是为了找到pos的前一个指针,我们只能通过遍历的方式;但是对于双链表我们pos->prev就直接找到上一个结点了!是不是更加的方便!!!
逻辑图:
我们首先要记住pos的前一个结点:prev = pos->prev,然后开始链接,prev->next = newnode,newnode->prev = prev,newnode->next = pos,pos->prev = newnode
具体代码:
逻辑测试:
在100前面插入1
逻辑测试没问题
10.任意删除:ListNodeErase
对于删除我们只需要一个参数,就是pos的地址,然后还需要记录它的前一个位置prev和后一个位置next,最终释放pos,让pos置空。
逻辑图:
根据上图进行链接,首先记住pos的前一个位置和后一个位置:prev = pos->prev,next = pos->next ;然后prev->next = next,next->prev = prev,free(pos),pos = NULL
具体代码:
逻辑测试:
删除数据100进行打印测试
逻辑测试没问题
11.计算大小:ListNodeSize
对于计算大小很简单,我们定义一个计数器count就可以了;只需要注意一点,我们是从第二个数据开始计算数据的大小,对于头节点是不算的:
具体代码:
逻辑测试:
统计此时数据的个数
4个数据,计算的大小也是4,逻辑测试没问题
12.销毁:ListNodeDestory
链表的销毁和顺序表不同,顺序表是连续的空间,free一次就可以;而链表创建的空间是不连续的,我们malloc多少次,就需要free多少次;并且我们最终也要把头指针(哨兵位)也要释放掉;下面看具体代码:
具体代码:
13.代码复用:ListNodeInsert和ListNodeErase
对于双链表虽然结构复杂,但是操作起来很简单;包括一些特殊情况:在单链表中空链表和一个节点的问题,在这里一个代码段就可以适合所有的结果;是不是很方便呢?那么我们在思考一个问题,能否用任意插入和任意删除去替代其它函数呢?
1.任意位置插入代替尾插:任意位置插,是在pos的前面插入,我们思考一下,在头指针的前面插入,不就相当于在尾插了吗?
具体代码如下:
测试结果也能得到我们的预期结果:
2.任意位置插入代替头插:
一直在头指针phead的next插入,不就相当于头插进行头插?
具体代码如下:
测试结果也能得到我们的预期结果:
3.任意位置删除代替尾删
对于尾删,我们只需要传过去尾指针:phead->prev
具体代码如下:
测试结果也能得到我们的预期结果:
4.任意位置删除代替头删
对于尾删,我们只需要传过去尾指针:phead->next
具体代码如下:
测试结果也能得到我们的预期结果:
14.所有具体代码:
总结:
还是那句话,对于链表的操作还是要动手画图!!!相对于单链表来说,双链表虽然结构复杂,但操作起来似乎更简单一点;无论是普通情况里面有很多元素,还是特殊情况空链表、一个节点的插入和删除;带头循环双链表都能用一段代码区解决;近乎完美。
这里我们大概写了10个常用的函数接口,希望对各位有所帮助;感兴趣的同学也可以写成项目工程的格式!!!
结束语
今天的分享就到这里,想要提升编程思维的,快快去注册牛客网开始刷题吧!各种大厂面试真题在等你哦!
💬刷题神器,从基础到大厂面试题👉点击跳转刷题网站