目录
我们的重点讲完了,你吸收了吗,看不懂就多看几遍,下面我们讲查找和展示。
listfind,这个函数我们找到了,我设置的是返回这个数据的地址,
所以这个想法是可以的实现的,但是具体有多大的用,我不是很清楚,这个仅仅是我分享我的一个想法
头
我们要知道双向链表的写法和使用,我们要先知道什么的双向链表吧。那你们知道吗。不需要抢答,想起来了吗,我们先来讲讲链表有多少种分类,怎么分,这个有点细节了,想得起来吗。想不起来也没关系,我们现在就讲,讲一句题外话这个双链表我认为核心是插入,所以要认真看插入。以及后面的改进和插入都有关系,这个有点长,请耐心。
链表的分类
链表分为,带头和不带头,循环和不循环,单向还是双向。而我们前面讲的单向链表就是不带头不循环单向的链表。而双向链表就是全部反过来,带头循环双向的链表。循环和双向可以理解但是带头是什么知道不,这个呢就是头节点(我们也叫哨兵位)这个节点,他不储存数据,他就起一个带头的作用,而为什么要这个带头呢,我猜可能是因为我们在后面加数据的时候要判断这个链表是不是为空,使用这个带头节点就不要判断了,可以减少代码(如果有人说减少不了什么代码,那我只能认为你写的只是一些小项目了),所以这个带头节点还是有用的。双链表的定义我们讲完了,你现在对双链表的认识有没有更深刻呢。
双链表的优点
虽然我们知道了双链表的定义,但是我们前面也学习了单链表,而双链表对比单链表有什么优势呢,反正我感觉,我以后应该不会用单链表了,因为双链表的功能包含了单链表,我们在写单链表的时候,我们有时候要尾节点是不是很麻烦,我们要从头节点开始next到尾节点,而双向链表就不用,因为双向链表是双向的使用我们可以用头节点的上一个节点,就可以得到尾节点了,是不是非常方便,而且双向链表是每一个都可以向前和向后访问,比单链表方便多了,他还有同节点,你都不要判断链表是不是为空。我把双链表吹的怎么高大上,你可以从里面看出双向链表怎么写吗
双向链表的写法
其实,上面说了怎么多,我们就可以看出两条,1,双向链表可以向前,向后访问。2,有头节点。知道了这两点我们就可以写了。首先,我们要一个存放数据的地方,这个存放数据的地方怎么写啊,看过我上一篇文章的兄弟爽了,这个类型我们可以单独定义出来,为了方便后面想要改。
后面就是两个指针了,一个指向前面的(prev),一个指向后面(next)这样我们就链表的元素就定义好了,看代码。

下面,我们就来讲双向链表的使用了
我们想我们写单链表的时候,我们写了哪些函数来对单链表进行操作,嗯……噢噢,增删查改,还有定义,销毁,再来一个展示,差不多了就这些。那我们就来对双链表进行这些操作。
首先,就是初始化,都没有初始化,怎么进行后面的操作啊,对不对。那问题来了,怎么初始化呢(换个说法就是我们想要初始化为什么样子呢),那我们就要想双链表的定义了,有一个头节点,然后链表是循环的,噢噢,我们要先申请了一个节点吗,嗯……,节点怎么申请。单链表里面就讲了哦,就是malloc嘛直接开辟,因为这个申请我们经常要用所以,我们也写一个函数,叫listbuy,我们又要注意了,我们的链表元素有两个指针,这两个指针指向哪啊,还是不指向了(也可以在后面具体使用的时候再指向,但是这个怕你忘了),但是双链表是循环的啊(一个都没开辟的情况),循环,噢噢噢,指向自己嘛,因此,我们就可以写出

listnode这个是定义的类型,我们虽然开辟了一个地方,为了以防万一还是要判断一下。
所以,我们就可以初始化了,我们先通过listnode得到一个节点(这个节点的指针还是指向自己的因此就不需要我们再操作了),这个就是头节点,就行了

为什么我这里要传-1,其实这里传什么都行,反正你不用就行。
有始有终,我们来写销毁,其实销毁也好写,我们单链表里面销毁怎么写的,是不是一个循环,一个一个空间来释放,就行了,这个的判断条件是指向为空的时候,我们双链表又没有指向为空,这是一个循环,哎,循环,那他走了一圈回来的时候停不就行了。噢,我们也写一个循环,那这个判断条件怎么写呢,虽然说走一圈但是,实际还是要想一下的,因此我画了一个图来理解,我们先创建两个指针,tem,not,为什么我们要两个,因为一个的话,我们如果先free,这里就为空了,就找不到后面的了,我们先往下走了,这里就没有free了,所以我们要两个指针。一开始是这样
然后写一个循环,我们的not先向后走,再free(tem),tem向后走……就到了
这时not的next为头节点了,但是头节点被free了,所以我们不能对他解引用,所以我们这时就要停下来,所以我们的判断条件就为not->next !=头节点(phead),但是我们虽然停下来了,我们还有两个没有free,也简单啊,再释放,就行了

还要把phead(头节点) 赋值为空噢,不然就是野指针了。
接下来就是插入了,要注意,这个插入他是分情况的,分什么情况呢,你也想想,闭眼想,
就是头插和尾插,就是这样你可能还是看不出区别,看图

我是这样认为你,如果你要反过来,我感觉也可以但是,双链表的全部插入就这两种(就是随机插入也和头插的写法是一样的),
我们先看尾插,

我们要把数据3尾插到2的后面去,我们应该怎么办,哎,这个和单链表有区别的啊,单链表的一部分可以借鉴,但是核心思想是一样的,那单链表的核心思想是什么,我感觉是指针,上一个的指针可以指向下一个,所以,我们可以参考一下,那这个是指针,或者说3加进来会影响哪些指针,我们,可以看到的是2的next指针要改,你能想到,phead(头指针)也会有影响吗,那有影响,我们就要改嘛,那我们来理一下改的思路,就是我们要找到原来链表的最后一个元素,这个怎么找,我们可以像单链表一样一个循环一直走到低吗,不能,为什么单链表到低是因为指向NULL才停下来,双链表是循环的一直不为空,哎,循环,那我直接phead的上一个不仅可以了,那
phead->prev不就可以表示原来链表的最后一个元素吗,那我们就可以把原来元素的最后一个和3连上了,就是phead->prev->next(这个可以理解吗,如果不能理解就把phead->prev看为一个指针(叫wei)就变为了wei->next)这个指针指向3(我把这个数据的名字叫jied)的地址就行了,我们再把jied->prev指向2就行了一半,对就是一半因为还有phead,把phead->prev指向哪里,对,指向newnode,再把newnode->next指向phead

我们一共赋值了4次,但是这4次,顺序可以乱,但是

要在
的前面,因为这个指针都被你改了,那他指向的地方就不是原链表的最后一个了。
尾插完了,头插,头插也是一样的套路。
一开始就是这样

像上面一样,我们利用phead的next找到,2,然后像上面一样插入。

和上面一样
要在
的前面,原因一样。
我们的重点讲完了,你吸收了吗,看不懂就多看几遍,下面我们讲查找和展示。
其实查找和展示的核心就是那个循环,你那个循环理解了(是理解不是直接写一样的,这两个还是有一点区别的),那你现在自己就可以写出来了,查找不就是在循环里面一个一个比较有一样的就返回那个数据的地址,找不到就返回NULL,然后展示就是在循环里面一个一个的printf,假如在跳出循环前有没有打印的,那就出循环后再打印,建议自己写一下尝试一下,我就直接放代码了

全部写好了,你测试一下,反正我测试没有任何问题。
双链表的改进
现在,我来讲一讲我对双链表的设想,我们在上面讲了插入,我们是不是分为了头插和尾插,也可以叫尾插和任意位置插入(包括头插),假如我写一个函数是不是还要判断他是不是尾插还是任意位置插入是不是有点复杂,那我们有没有办法写一个函数是他尾插和任意位置插入都可以,不知道,对我不知道这个我没有想出来,但是我想我把双链表改一下,就可以实现尾插和任意位置插入都行,所以我们来实现一下
这个叫什么我不知道,在这里我还是叫他双链表,但是现在的所有双链表都不是我们认为的那个双链表了,而是我自定义的双链表。那是怎么定义的呢。
你想我们为什么会写出任意位置插入和尾插,就是因为我们有头节点,所有我们就要改这个头节点,但是我们为什么要这个头节点,不就是因为不要判断链表是不是为空吗,那这个头节点我们就不能删除他,不能删除他,那我们又能怎么改呢,既然删除不了,那就再加一个尾,一个头一个尾不就可以了,所有我自己改的链表就是在初始化的时候,我再加一个尾节点,这样就不要分任意位置插入和尾插了。
我们就先来初始化一下,我们可以用上面的listbuy函数得到二个节点,但是双链表是循环的啊,所有我们就把这两个节点连接起来,就好了。我们就初始化为了我们想要的一个头,一个尾节点。

这里为什么传-1和-2,不为什么,因为爱一个人不需要理由。所以这里你只需要传一个你喜欢但是不常用的数据就行了。销毁还是和上面一样一个循环就行了
现在我们来写我们改后的插入,因为这个不需要分头插还是尾插,所以我直接写任意位置插入
函数是
![]()
list*pos这个是你要插的位置,假如你要插在头节点的后面你就传头节点,你要插在谁的后面你就传谁。x就是你要插的数据。现在我们就来写

假如链表为空一开始是这样的,我们只能插头节点的后面,你不能插尾节点后面(我是这样认为的,因为没有什么意义),其实链表不为空也是可以的。

我们想要把数据1(newnode)插入头节点后面,我们就要改他两边的指针,这里我们只能通过头节点的下一个节点,(有没有小聪明想到用头节点的上一个节点也可以找到尾节点,你真厉害,但是没用,我是要头节点的下一个节点,这个节点不一定是尾节点)所以我们先通过头节点找到头节点的下一个节点就是phead->next,这个就是现在的尾节点我们就按照,上面的
把newnode和phead->next连起来就行了,再连
就行了,但是顺序不能反,反了就不能用phead->next找到我们想要的节点了

这个是代码,但是我们的设想的不是为空,我们是要这个函数在任意位置都可以插入,但是你看这个函数就可以在任意位置插入了后面我测试给你们看,测试之前你要你们找到,我怎么传一个指定位置吗,这个链表每一个的元素地址我都不知道,怎么传。但是我们前面已经给了方法,那就是listfind,这个函数我们找到了,我设置的是返回这个数据的地址,所以我们就可以用这个函数来得到数据的地址,而这个函数的核心思路还是循环(这个循环你可能看起来简单,但是要你真正的写了,才可以理解他每一个的奥妙),我就直接放代码了,

还有展示函数和原来的双链表差不多,

现在我们就可以来调试了,我们先调试头插

可以看到没有问题,那我们再来找数据

可以看到我要找两个数据都找到了,并且地址返回了那现在我们在这个地址后面加数据,注意我的链表是4是头节点的next,1是尾节点的上一个节点

344



被折叠的 条评论
为什么被折叠?



