前面说过在需要不停的找前驱时(删除要找前驱等等),其时间复杂度很大。
这个图就是双向链表,相当于2个(方向相反的)单链表合起来
所以双向链表的结构设计就是比单链表多了一个指针域,以空间换时间,减小时间复杂度
DList指向整个表,DNode指向头结点,头结点后面串起了整个表,所以虽然两个的含义不同,但在计算机里面的用法是等价的,都是代表整个表
结构设计看图;
初始化看结构内部成员有无影响
也就是
测试
头插函数(插入在头结点后面的第一个有效数据的位置上)
思路:
1.创建一个新结点,将val数值丢进去
2.将新结点连接进去。可以分开接,先接上面那条线。那就跟原来的单链表连接方式一样了
先绑后面(箭头后面),再绑前面
然后反过来接下面那条线,一共4条线,注意先后顺序
第一句话一定在最上面,剩下3句的顺序可更改
1.p的next置为500,p的NULL变为500——p->next = plist->next;
2.plist的next置为800,plist的500变为800——plist->next = p;
3.p的prio置为100,p的NULL变为100——p->prio = plist;
4.p的next的prio中的100变为800——p->next->prio = p;
可以照着单链表的头插写
malloc之后要加断言
测试
为负数,代码崩溃了
代码崩溃的主要原因之一就有——访问了空的指针,特别是在什么的什么的什么,这样的多级指针时,其中某一级指针为空时,整句代码都将崩溃。
下面排查一下头插函数中,有没有指针为空的情况
第一句:如果当p为空时,访问p的next就会崩溃。
但在创建新结点p时,就断言了p不为空。所以p不可能为空。
(p不为空,则访问p的next或是访问p的prio都没错)
而plist在一进入函数开始就断言了不为空。
所以第一句没错
第二句:不为空,也没错
第三句:不为空,也没错
第四句:如果当p->next为空时,访问p->next的prio就会崩溃
恰好p->next就有为空的可能情况,即在只有一个plist头结点的情况下,
此时plist->next就为空,再经过第一句
之后,此时p->next就是空
那么访问p->next的prio就会崩溃
第一句
第二句:上边的单链表已经串起来了
第三句:此时已经完成了双向链表的连接
此时就不需要绑第(4)条线了,即不执行第四句话了
所以上面的测试中,在插入第一个i(头结点后第一个i)时,程序就已经崩溃了
综上所述,问题出在我们需要判断第四句话什么时候不需要执行(在只有一个头结点plist的双向链表中进行头插),什么时候需要执行。所以我们要给它加上执行条件
测试
先写一个Show输出函数
测试