前言
在前面的文章中,我们已经学习了单链表,但是对于单链表有一个很大的问题就是,单链表只能找到后继结点,无法返回找到前驱。那么这一片文章中双链表就能很好的解决这个问题。
单链表 vs 双链表
双链表就是在单链表的基础上增加了前驱指针
typedef struct DNode{ // DNode(Double Node)
ElemType data; // 数据域
struct DNode *prior,*next; // 前驱和后继指针
}DNode,*DLinklist;
双链表的初始化
typedef struct DNode{ // DNode(Double Node)
ElemType data; // 数据域
struct DNode *prior,*next; // 前驱和后继指针
}DNode,*DLinklist;
bool InitDLinkList(DLinkList &L){
L = (DNode *)malloc(sizeof(DNode)); // 分配一个头结点
if(L==NULL) // 内存不足,分配失败
return false;
L->prior = NULL; // 头结点的前继指针指向NULL
L->next = NULL; // 头结点的后驱指针指向NULL
return true;
}
void testDLinkList(){
DLinklist L;
InitDLinkList(L);
}
如上述代码初始化后形成的头节点如下图:
判断双链表为空
判断链表是否为空,判断头结点后继指针是否为NULL
bool Empty(DLinklist L){
if(L->next==NULL)
return true;
else
return false;
}
双链表的插入
双链表插入新结点步骤:
- 将新结点的前驱指针指向上一个结点,后继指针指向下一个结点
- 将前继结点的后驱指针指向新结点
- 将后驱结点的前继指针指向新结点
bool InsertNextDNode(DNode *p,DNode *s){
if(p==NULL || s==NULL) // 非法参数
return false;
s->next = p->next;
if(p->next!=NULL) // 如果p结点有后继结点
p->next->prior=s; // 将后继结点的前驱指针指向新结点
s->prior = p;
p->next = s;
return true;
}
上面为什么要判断if(p->next!=NULL)
呢?
因为如果我们是在链表的尾部插入结点的话,那么链表的最后一个元素的后继指针指向的是NULL(没有后继结点)那么就不存在后继指针的结点的前驱指针。
其实上述就是我们在单链表中讲述过的后插操作,只要实现了这个后插操作,就可很方便的实现其它的操作:
- 按位序插入
- 找到需要插入的位置的前继结点,再对这个结点进行后插操作即可
- 前插操作
- 找到给定结点的前驱结点,对前驱结点进行后插操作即可
双链表的删除
删除的步骤:
- 将要删除的结点的前驱结点的后继指针指向,要删除的结点的后继指针指向的结点
- 将要删除的结点的后继结点的前驱指针指向,要删除的结点的前驱指针指向的结点
- 使用
free()
函数释放要删除的结点
为了加强代码的健壮性,我们还需要加入一些判断:
- 判断要删除的该节点是否有后继节点
bool DeleteNextNode(DNode *p){
if(p==NULL) return false; // 判断p结点是否存在
DNode *q = p->next; // 找到p结点的后继结点
if(q==NULL) return false; // 判断p的后继节点是否存在(q为要删除的结点)
p->next = q->next;
if(q->next!=NULL) // 判断q结点是否是链表中的最后一个结点
q->next->prior = p;
free(q)
return true;
}
销毁双链表
想要销毁双链表,首先要使用循环将链表中的结点一个个删除,最后将头结点释放。
void DestoryList(DLinklist &L){
while(L->next!=NULL)
DeleteNextDNode(L);
free(L); // 释放头结点
L = NULL; // 头指针指向NULL
}
双链表的遍历
前向遍历
while(p!=NULL){ // 将判断条件变为 p->prior!=NULL 则会跳过头结点
p = p->prior;
}
后向遍历
while(p!=NULL){
p = p->next;
}
时间复杂度
由于双链表不可进行随机存取,故按位查找、按值查找操作都只能用遍历的方式实现,时间复杂度为O(n)
结束语
已同步更新至个人博客:https://www.hibugs.net/index.php/dlinklist/
本人菜鸟一枚,仅分享学习笔记和经验。若有错误欢迎指出!共同学习、共同进步 😃
如果您觉得我的文章对您有所帮助,希望可以点个赞和关注,支持一下!十分感谢~(若您不想也没关系,只要文章能够对您有所帮助就是我最大的动力!)
下一篇文章传送门:正在更新,敬请期待…