news 2026/5/19 7:49:57

【手撕数据结构】拿捏双向链表

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【手撕数据结构】拿捏双向链表

目录

  • 链表介绍
  • 初始化链表
  • 销毁链表
  • 查找节点
  • 打印链表
  • 增加节点
    • 尾插
    • 头插
    • 在指定位置之后插入节点
  • 删除节点
    • 尾删
    • 头删
    • 删除指定位置节点
  • 链表判空

链表介绍

前面说到,链表的结构一共有八种:带头单向循环链表、带头单向非循环链表、带头双向循环链表、带头双向非循环链表、无头单向循环链表、无头单向非循环链表、无头双向循环链表、无头双向非循环链表。
在这八种结构中,我们只挑两种来进行刨析,即无头单向非循环链表和带头双向循环链表。

而今天我们要介绍的双向链表就是带头的,头结点head也被称为哨兵位,如果链表为空,则链表只有一个哨兵位。双向链表的结构为

typedefintLTDataType;//方便以后修改双向链表存储的数据类型typedefstructListNode{LTDataType val;structListNode*prev;structListNode*next;}LTNode;

分别用一个变量存储数据,前驱指针prev指向前节点,next指针指向后节点,这样链表就可以进行随机访问。

初始化链表

LTNode*LTBuyNode(LTDataType x)//尾插,头插等都需要创建新的节点,不妨封装一个函数,每个节点的next,prev指针都先指向自己,{LTNode*newnode=(LTNode*)malloc(sizeof(LTDataType));if(newnode==NULL){perror("malloc failed");exit(1);}newnode->val=x;newnode->prev=newnode->next=newnode;returnnewnode;}

因为插入都需要创建节点,所以封装一个函数
注意:这些节点的next指针和prev指针都指向自己,这是为了兼容空链表只有一个哨兵位时,和后面插入节点时利用这两个指向自己的指针调成被影响的节点的指针

//void LTInit(LTNode** pphead)//{// assert(pphead);// *pphead = LTBuyNode(-1);//}//优化接口一致性版本LTNode*LTInit(LTNode*phead){LTNode*newnode=LTBuyNode(-1);returnnewnode;}

首先,我们要对链表进行初始化,上面说了空双向链表是只有一个哨兵位,所以我们创建一个节点作为哨兵位.

销毁链表

//void LTDestroy(LTNode** pphead)//{// assert(pphead && *pphead); //*pphead防止释放空链表// LTNode* pcur = (*pphead)->next;// while (pcur != *pphead)// {// LTNode* Next = pcur->next;// free(pcur);// pcur = NULL;// pcur = Next;// }// free(*pphead);// *pphead = NULL;//}//优化接口一致性版本voidLTDestroy(LTNode*pphead){assert(pphead);LTNode*pcur=pphead->next;while(pcur!=pphead){LTNode*Next=pcur->next;free(pcur);pcur=NULL;pcur=Next;}free(pphead);pphead=NULL;//这里设置NULL了不影响实参,需要手动设置NULL,但是释放了空间是同一块空间,}

销毁链表,从头结点的后一个结点处开始向后遍历并释放结点,直到遍历到头结点时,停止遍历并将头结点也释放掉。

查找节点

LTNode*LTFind(LTNode*phead,LTDataType x){assert(phead);if(!LTEmpty(phead)){returnNULL;}else{LTNode*pcur=phead->next;while(pcur!=phead){if(pcur->val==x){returnpcur;}pcur=pcur->next;}}returnNULL;}

给定一个值,在链表中寻找与该值相同的结点,若找到了,则返回结点地址;若没有找到,则返回空指针(NULL)。如果为空链表,就直接返回NULL.这里因为双向楼面是循环的,用pcur从头结点(哨兵位下一个节点)开始遍历,如果回到哨兵位表示已经查找完一圈,没找到。

打印链表

voidLTPrint(LTNode*phead){assert(phead);LTNode*pcur=phead->next;while(pcur!=phead){printf("%d->",pcur->val);pcur=pcur->next;}}

打印双向链表时也是从头结点的后一个结点处开始向后遍历并打印,直到遍历哨兵位结点处时便停止遍历和打印(哨兵位结点数据不打印)。

增加节点

尾插

voidLTPushBack(LTNode*phead,LTDataType x){assert(phead);LTNode*newnode=LTBuyNode(x);newnode->next=phead;newnode->prev=phead->prev;phead->prev->next=newnode;phead->prev=newnode;}

尾插,申请一个新结点,将节点插入到旧尾节点之后,改变旧尾节点的next指针和新尾节点的next指针和prev指针,改变哨兵为的prev指针

头插

voidLTPushFront(LTNode*phead,LTDataType x){assert(phead);LTNode*newnode=LTBuyNode(x);newnode->next=phead->next;newnode->prev=phead;phead->next->prev=newnode;phead->next=newnode;}

头插,即申请一个新结点,将新结点插入在哨兵位后即可。

在指定位置之后插入节点

voidLTInsert(LTNode*pos,LTDataType x){assert(pos);LTNode*newnode=LTBuyNode(x);newnode->next=pos->next;newnode->prev=pos;pos->next->prev=newnode;pos->next=newnode;}

我们只需申请一个新结点插入到指定位置结点和其后一个结点之间即可。

删除节点

尾删

voidLTPopBack(LTNode*phead){assert(phead);assert(LTEmpty(phead));LTNode*del=phead->prev;del->prev->next=phead;phead->prev=del->prev;free(del);del=NULL;}

头删

头删,即释放哨兵位的后一个结点,并建立哨兵位节点与被删除结点的后一个结点之间的双向关系即可。

voidLTPopFront(LTNode*phead){assert(phead);assert(LTEmpty(phead));LTNode*del=phead->next;phead->next=del->next;del->next->prev=phead;free(del);del=NULL;}

删除指定位置节点

voidLTErase(LTNode*pos){assert(pos);pos->prev->next=pos->next;pos->next->prev=pos->prev;free(pos);pos=NULL;}

删除指定位置结点,释放掉目标结点后,建立该结点前一个结点和后一个结点之间的双向关系即可。

链表判空

boolLTEmpty(LTNode*phead){assert(phead);returnphead->next!=phead;}

链表判空,即判断头结点的前驱或是后驱指向的是否是自己即可(因为是循环)

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/2 5:40:57

Ventoy制作多系统启动盘:包含Ubuntu安装与Qwen3.5-4B部署指南

Ventoy制作多系统启动盘:包含Ubuntu安装与Qwen3.5-4B部署指南 1. 前言:为什么需要多功能启动盘 对于经常需要在不同机器上部署环境的开发者或教师来说,随身携带一个多功能启动盘能极大提升工作效率。想象一下,当你需要在新机器上…

作者头像 李华
网站建设 2026/4/2 5:37:44

cv_unet_image-colorization部署案例:RTX显卡5分钟搭建AI上色工作站

cv_unet_image-colorization部署案例:RTX显卡5分钟搭建AI上色工作站 1. 项目简介 你是否遇到过这样的情况:翻看老照片时,发现很多珍贵的黑白照片已经褪色发黄,想要恢复色彩却不知道从何下手?或者作为摄影师&#xff…

作者头像 李华
网站建设 2026/4/2 5:35:05

零代码部署FireRedASR-AED-L:本地语音识别,保护隐私数据

零代码部署FireRedASR-AED-L:本地语音识别,保护隐私数据 1. 工具简介 今天要介绍的是一个能让你在本地电脑上运行的专业级语音识别工具——FireRedASR-AED-L。这个工具最大的特点是完全在本地运行,不需要联网,你的所有音频数据都…

作者头像 李华
网站建设 2026/4/2 5:34:24

MusePublic圣光艺苑企业应用:文旅景区AI海报批量生成解决方案

MusePublic圣光艺苑企业应用:文旅景区AI海报批量生成解决方案 1. 引言:当古典艺术遇见现代文旅营销 想象一下,一个大型文旅集团旗下有几十个景区,每个景区在不同季节、不同节日都需要更新宣传海报。传统的设计流程是怎样的&…

作者头像 李华