这是C++算法基础-数据结构专栏的第二十篇文章,专栏详情请见此处。
引入
上次我们学习了单链表,单链表中的每个节点都只存储了它们的下一个节点,只能从前往后遍历,而双链表中的每个节点都存储了它们的上、下两个节点,不仅能从前往后遍历,还能从后往前遍历。
下面我们就来讲双链表的实现。
双链表与单链表的性质是大致相同的,如果想了解具体内容,可以移步至我的这篇博客:单链表的实现。
在这里就不再详细讲解,只讲解定义和主体过程qwq
定义
链表的定义也在单链表的实现里讲解了,不再详细讲解。
双向链表中同样有数据域和指针域。与单链表不同之处在于,指针域有左右(或上一个、下一个)之分,用来连接上一个结点、当前结点、下一个结点。它的主要用途是优化某些问题。
过程
双链表对于过程的说明也在单链表的实现里讲解了,不再详细讲解。
双链表的最主要操作有三个:构建、插入(写入)数据和删除数据。
构建双链表
与单链表不同的是,除了存储每个节点的值的,对于连接节点的数组,需要用到和两个数组,分别存储了每个节点的上一个节点的下标和下一个节点的下标;接着,本来我们需要创建一个头结点和尾结点的,但我们这次偷个懒,将下标为的位置分配给,将下标为的位置分配给,它们只有一个指向:指向后一个节点,指向前一个节点,刚开始它们互相指向对方,链表中有节点后头结点就指向第一个节点,尾结点就指向最后一个节点;其次还需要一个变量,表示当前节点的下标,刚开始需要赋值为(想一想为什么)。
向链表中插入(写入)数据
向节点后插入一个节点的流程大致如下:
- 在节点的中存储数值;
- 将节点的存储为;
- 将节点的存储为节点所存储的;
- 将节点所存储的的存储为;
- 将节点的存储为。
首先,图一展示了起始状态;然后,在新节点上面储存数据(第一步,图二);由于新节点要插在节点后, 节点所存储的下一个节点前,所以新节点的上一个节点要赋值为节点,下一个节点要赋值为节点所存储的下一个节点(第二、三步,图三);最后,节点所存储的下一个节点的上一个节点要赋值为节点,节点的下一个节点要赋值为节点(第四、五步,图四)。
还有一点需要注意,操作完成后需要,以便进行下一个节点的插入。
除了向节点后插入一个节点,也有向头节点后插入一个节点和向节点前插入一个节点的操作,这三者虽然代码实现有所不同,但是思路大同小异,那后两者的代码就不再展示了,留给读者去思考。(删除数据也有类似操作,后面也不再讲解)
向链表中插入(写入)数据
将节点后的节点删除的流程大致如下:
- 将节点所存储的所存储的的 存储为;
-
将节点的存储为节点所存储的所存储的。
首先,图一展示了起始状态;然后, 节点所存储的下一个节点所存储的下一个节点的上一个节点要赋值为节点,节点的下一个节点要赋值为节点所存储的下一个节点所存储的下一个节点(第一、二步,图二)(懵(⊙_⊙)?)。
代码
下面给出双链表的实现代码:
int e[N],l[N],r[N],idx;
void init(){
l[1]=0;
r[0]=1;
idx=2;
}
void add(int k,int x){
e[idx]=x;
l[idx]=k;
r[idx]=r[k];
l[r[k]]=idx;
r[k]=idx++;
}
void remove(int k){
l[r[r[k]]]=k;
r[k]=r[r[k]];
}
代码解释
第一行的各种变量和数组已经在前面讲解了,这里不再详细讲解;init()函数的作用是初始化;add()函数的作用是将插到下标是的节点后面;remove()函数的作用是将下标是的节点后面的节点删掉。
上一篇-单链表的实现 C++算法基础专栏文章 下一篇-栈的实现.
每周六更新一篇文章,内容一般是自己总结的经验或是在其他网站上整理的优质内容
点个赞,关注一下呗~