双向链表专题

双向链表

  • 1. 双向链表的定义和结构
  • 2. 双向链表的实现
    • 2.1 结构声明
    • 2.2 双向链表的初始化
    • 2.3 双向链表的打印
    • 2.4 尾插
    • 2.5 头插
    • 2.6 在指定位置之前插入
    • 2.7 在指定位置之后插入数据
    • 2.8 尾删
    • 2.9 头删
    • 2.10 删除指定位置的节点
    • 2.11 查找
    • 2.12 链表的销毁
  • 3. 双向链表的细节

  

🔥 博客主页: 偷心编程
🎥 系列专栏: 《Java学习》 《C语言学习》 《数据结构C语言版》
❤️ 感谢大家点赞👍收藏评论✍️
在这里插入图片描述
在这里插入图片描述

  

1. 双向链表的定义和结构

  我们在前面就说了链表最常用的两种结构就是 “单链表”(无头单向不循环链表)以及 “双向链表”(有头双向循环链表),掌握了这两种方法,其他类型的链表也可以定义出来。

  在单链表中的头结点与双向链表中的头结点不太一样!单链表中的头结点是指——第一个有效数据,这个头结点可以改变也可以为NULL;但是双向链表中的头结点是指——“哨兵位”节点,一定存在,并且这个节点不存储有效数据,是不可以改变的。

在这里插入图片描述

2. 双向链表的实现

2.1 结构声明

typedef int LTDataType;
//定义双向链表节点的结构
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;
}LTNode;

2.2 双向链表的初始化

  1. 直接在main创建头结点,并且给其里面数据初始化在这里插入代码片
int main()
{LTNode* head = (LTNode*)malloc(sizeof(LTNode));if (!head){perror("malloc:");exit(1);}head->data = -1;head->next = head->prev = head;return 0;
}
  1. 自定义BuyNode函数进行初始化
//申请一个节点
LTNode* BuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (!node){perror("malloc:");exit(1);}node->data = x;node->prev = node->next = node;return node;
}int main()
{LTNode* head = BuyNode(-1);return 0;
}

总之双向链表一定要创造一个不为空的头结点(哨兵位)
其次在创造新的节点的时候,指向前面后面的两个节点指针并不等于NULL,而是指向自己本身,这样才体现了循环

2.3 双向链表的打印

//链表的打印
void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;//处理链表只有头结点的情况if (pcur == phead){printf("链表没有有效数据!");return;}//处理一般情况while (pcur != phead){printf("%d ", pcur->data);pcur = pcur->next;}printf("\n");
}

2.4 尾插

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{//获取新的节点LTNode* newnode = BuyNode(x);//获取尾节点LTNode* ptail = phead->prev;newnode->prev = ptail;newnode->next = phead;ptail->next = newnode;phead->prev = newnode;
}

2.5 头插

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{//获取新的节点LTNode* newnode = BuyNode(x);newnode->prev = phead;newnode->next = phead->next;newnode->next->prev = newnode;newnode->prev->next = newnode;
}

2.6 在指定位置之前插入

//在指定位置之前插入
void LTInsertFront(LTNode* pos, LTDataType x)
{//获取新的节点LTNode* newnode = BuyNode(x);newnode->prev = pos->prev;newnode->next = pos;newnode->prev->next = newnode;newnode->next->prev = newnode;
}

2.7 在指定位置之后插入数据

//在指定位置之后插入
void LTInsertBack(LTNode* pos, LTDataType x)
{//获取新的节点LTNode* newnode = BuyNode(x);newnode->prev = pos;newnode->next = pos->next;newnode->prev->next = newnode;newnode->next->prev = newnode;
}

2.8 尾删

//尾删
void LTPopBack(LTNode* phead)
{//链表至少要有头结点和一个有效元素assert(phead && phead->next != phead);//获取要删除的节点LTNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}

2.9 头删

//头删
void LTPopFront(LTNode* phead)
{//链表至少要有头结点和一个有效元素assert(phead && phead->next != phead);//获取要删除的节点LTNode* del = phead->next;del->next->prev = phead;phead->next = del->next;free(del);del = NULL;
}

2.10 删除指定位置的节点

//删除指定位置的节点
void LTDelete(LTNode* pos)
{pos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);pos = NULL;
}

2.11 查找

//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}printf("没有找到目标元素!\n");return	NULL;
}

2.12 链表的销毁

//链表的销毁
void LTDesTroy(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//头结点也要销毁free(phead);//并没有真正将头结点置为空phead = NULL;
}

3. 双向链表的细节

  1. 由于双向链表的头结点不会改变,所以我们在实现各类方法的时候都是传入一级指针,而不是二级指针

  2. 不难从尾插方法看出,由于双向链表的结构特性,我们除了打印链表、查找和销毁链表需要进行循环,其他的方法我们很少用到循环(比如找尾节点)

  3. 我们在插入一个节点的时候,同样是先改变外部环境(新创建的节点),最后再改变内部环境(插入位置前后节点的prev或next)

固定套路:

newnode->prev = pos;
newnode->next = pos->next;
//newnode前一个节点
newnode->prev->next = newnode;
//newnode后一个节点
newnode->next->prev = newnode;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8005.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

发票真伪查验方式-python数电票批量查验接口、发票ocr文字识别提取

在当今的商业环境中,确保交易的安全性和透明度是每个企业追求的目标。随着电子商务的迅猛发展,发票管理成为了企业财务管理中不可或缺的一环。面对海量的电子发票,企业财务也无需惊慌,翔云发票查验API接口,可以为企业提…

html+js+css实现拖拽式便签留言

前些日子在网上冲浪时,看到一个便签式留言墙,让人耳目一新。心想这个看着不错,额想要。于是便开始搜寻是否有相应开源插件,想将其引入自己的博客中。但是搜寻了一圈,都没有符合预期的,要么功能不符合。有的功能符合&am…

初识网络编程TCP/IP

目录 前言相关名词解释应用层协议——HTTP传输层协议socketTCP帧头格式三次握手、四次挥手 UDPTCP的socket实现 参考博文 前言 刚碰到网络编程,会出现一堆协议、概念、这层次那技术的,头都大了,还是得总结总结…… 相关名词解释 ✨✨网络…

Vue2进阶之Vue3高级用法

Vue3高级用法 响应式Vue2:Object.definePropertyObject.definePropertythis.$set设置响应式 Vue3:Proxy composition APIVue2 option API和Vue3 compositionAPIreactive和shallowReactivereadonly效果toRefs效果 生命周期main.jsindex.htmlLifeCycle.vue…

树叶分类竞赛(Baseline)以及kaggle的GPU使用

树叶分类竞赛(Baseline)-kaggle的GPU使用 文章目录 树叶分类竞赛(Baseline)-kaggle的GPU使用竞赛的步骤代码实现创建自定义dataset定义data_loader模型定义超参数训练模型预测和保存结果 kaggle使用 竞赛的步骤 本文来自于Neko Kiku提供的Baseline,感谢大佬提供代码…

与C语言的旅程之分支与循环(2)

与C语言的旅程之分支与循环 C语⾔是结构化的程序设计语⾔,这⾥的结构指的是顺序结构、选择结构、循环结构, 目录 与C语言的旅程之分支与循环 1. if语句 1.1 if ​编辑1.2 else 1.3 分⽀中包含多条语句 1.4 嵌套if 1.5 悬空else问题 2. 关系操作符…

springBoot 自动配置与starter

目录 一、自动配置 Springboot实现自动配置的核心机制 Conditional的作用是什么? 如何自定义自动配置? 步骤 例子分析 自动配置的优先级 如何禁用特定的自动配置? 二、starter 如何理解Spring Boot中的starter? 如何自…

《Python编程实训快速上手》第三天--字典和结构化数据

一、字典 1、字典数据类型介绍 myCat {"size":"fat","color":"gray"} 特征: 字典输入时带上{}字典中每一个值是以键值对形式存在,先写键,再写值 2、字典与列表 列表索引必须是整数,字…

Pinia小菠萝(状态管理器)

Pinia 是一个专为 Vue 3 设计的状态管理库,它借鉴了 Vuex 的一些概念,但更加轻量灵活。下面将详细介绍如何使用 Pinia 状态管理库: 安装 Pinia 使用 npm:在项目目录下运行npm install pinia。使用 yarn:在项目目录下运…

【智能算法应用】哈里斯鹰算法优化二维栅格路径规划问题

摘要 本文研究了基于哈里斯鹰优化算法(Harris Hawks Optimization, HHO)的二维栅格路径规划方法。HHO算法模拟哈里斯鹰的猎食行为,通过迭代搜索过程找到从起点到终点的最优路径,避开栅格中的障碍物。实验结果表明,HHO…

vue/react做多语言国际化的时候,在语言配置中不同的语言配置不同的字体,动态引入scss里面

如果想直接在vue文件的css里面使用,就可以使用i18n的t函数,注意t外层也有引号: font-size: v-bind("t(style.teamCurModelFontSize)"); 前提是要引入t函数:

优衣库在淘宝平台的全方位竞品分析与店铺表现研究:市场定位与竞争策略透视

优衣库品牌在淘宝平台的全方位竞品与店铺表现分析 一、品牌商品分析 1.商品列表与分类分析(数据来源:关键词商品搜索接口;获取时间:2024.08.30) 商品类别分布柱状图: 根据关键词商品搜索接口获取到的优衣…

spark新能源汽车推荐系统-计算机设计毕业源码42422

摘要 本论文致力于探讨基于Spark技术的新能源汽车推荐系统新能源汽车分析及可视化内容。系统将严格按照软件开发流程进行各个阶段的工作,利用Python编程语言中的爬虫功能,实现对懂车帝的汽车信息数据的爬取,作为系统的数据来源,并…

Element UI组件Dialog显示闪动问题【解决方案】

在ElementUI中,el-dialog弹窗确实有时会导致页面出现抖动或闪动的问题。这通常是由于弹窗出现时对页面布局的影响,特别是滚动条的出现或消失,导致了页面的重新布局和渲染。以下是一些解决或缓解这一问题的方法: 解决方案 1. 关闭…

SpringBoot技术在企业资产管理中的应用

4系统概要设计 4.1概述 系统设计原则 以技术先进、系统实用、结构合理、产品主流、低成本、低维护量作为基本建设原则,规划系统的整体构架. 先进性: 在产品设计上,整个系统软硬件设备的设计符合高新技术的潮流,媒体数字化、压缩、…

月GMV2000W+,在视频号“开超市”也太赚了吧!

今年的视频号双11,似乎更低调了。 ▲ 图片来源:视频号 从官方的双11专栏来看,今年改叫“微信小店11.11好物节”。 今年618时候,还有专门的带货榜单,并且细分为“今日带货榜单、带货总榜、品牌带货榜、达人带货榜”&…

xlsx.js 读取excel文件

需求:读取一个excel文件。 一、 使用antd的Upload组件的 【customRequest】方法。 互斥。此方法跟【onChange】方法互斥,即:不可同时出现。调用次数不一样。onChange方法会根据文件当前的上传状态从而被调用多次(读取中&#xff…

华为云创建ECS前台展示规格类型选项是怎么做到的?

前台展示很多规格可选,怎么做到的?先了解规格其实都是管理员在后台service_OM创建好规格 1.规格 1.1设置自定义标签打通规格和主机组还能体验调度功能 引申:AZ可用分区(为了做容灾) 为什么在界面可以让我√az0.dc0,在填工程参数openstack region信息已写 AZ间存储不能共…

我们来学mysql -- 同时使用 AND 和 OR 查询错误(填坑篇)

AND 和 OR 一同使用问题 现象分析处理扩展 现象 业务上在“锁定”当前零件所在出口国的所有零件时,出现其他国家零件 问题定位 分析 or 切断了操作符之间的连续性,从union角度分析 where k1 Td621 and k1 Vda96 or k3 P00009等同 select * fr…

Python入门:了解 Python 中 globals() 和 types 的用法

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 使用 `globals()` 获取当前作用域信息📝 使用 `types` 模块判断函数类型📝 `globals()` 与 `types` 结合使用📢 综合示例📝 总结⚓️ 相关链接 ⚓️📖 介绍 📖 在 Python 中,动态获取当前作用域…