深入探究:在双链表的前面进行插入操作的顺序

 

归纳编程学习的感悟,
记录奋斗路上的点滴,
希望能帮到一样刻苦的你!
如有不足欢迎指正!
共同学习交流!
🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝

惟有主动付出,才有丰富的果实获得收获!

  

前言:

        在学习数据结构与算法的课程中,单链表的插入操作只用操作两个指针就可以完成操作,因为单链表就一个next的指针域可控操作,但是在双链表中新加了prior指针域,这会使我们在进行插入操作时需要进行4步的改变指针指向操作才能完成,也就是说如果将这4个步骤的顺序全排列,就会出现4!= 24种进行双链表插入操作的顺序。但是这24种情况只有12种可以成功插入的,为什么是12种,以及为什么另外12种会插入失败,还有在考试中如何快速判断题目给出的顺序是否正确?这些问题我们在正文中进行详细的讲解。

        注意:本章节讲的只是p指向待插入元素的后面,所以后面讲的结论只适用于往p指向的结点前面插入一个元素,关于p指向待插入元素的前面的规律,我会在明天发文总结!!!

一、我们先展示代码

#include<stdio.h>
#include<stdlib.h>

#define DataType int
#define debug(a) printf("%d ",a)

// 宏定义简化了插入操作中的四个关键步骤
#define one s->prior=p->prior  // 新节点s的前驱指向p的前驱
#define two p->prior->next=s    // p的前驱的后继指向新节点s
#define three s->next=p         // 新节点s的后继指向p
#define four p->prior=s         // p的前驱指向新节点s

// 双链表结点结构体定义
typedef struct DLNode
{
	DLNode *prior;  // 指向前一个结点
	DLNode *next;   // 指向后一个结点
	DataType data;  // 存储的数据
}DLNode,*DLinkList; 

// 初始化双链表头结点
void InitDLinkList(DLinkList *head);
// 创建双链表
void CreatDLinkList(DLinkList head,int a[]);
// 在第i个位置前面插入元素e
int InsertElem(DLinkList head,int i,DataType e);
// 打印双链表
void printElem(DLinkList head);

int main()
{	
	int a[10]={10,20,30,50,60,70,80,90};
	DLinkList L;
	InitDLinkList(&L);  // 初始化双链表
	CreatDLinkList(L,a);  // 根据数组创建双链表
	printElem(L);  // 打印双链表
	InsertElem(L,4,40);  // 在第4个位置插入40
	printElem(L);  // 再次打印双链表
	return 0;
} 

// 初始化双链表头结点
void InitDLinkList(DLinkList *head)
{
	if((*head=(DLNode*)malloc(sizeof(DLNode)))==NULL)
	{
		exit(-1);  // 如果内存分配失败则退出程序
	};
	(*head)->next=NULL;  // 头结点的next设为NULL
}

// 根据整型数组创建双链表
void CreatDLinkList(DLinkList head,int a[])
{
	DLNode *p,*s;
	p=head;  // p初始化为头结点
	for(int i=0;i<8;i++)  // 循环创建8个数据结点
	{
		s=(DLNode*)malloc(sizeof(DLNode));  // 分配新结点
		s->data=a[i];  // 设置新结点的数据
		p->next=s;  // 将新结点链接到p后面
		s->prior=p;  // 设置新结点的前驱为p
		s->next=NULL;  // 新结点的next设为NULL
		p=s;  // 移动p到新结点
	}
}

// 在双链表的第i个位置插入元素e
int InsertElem(DLinkList head,int i,DataType e)
{
	DLNode *p;
	p=head;  // 从头结点开始
	int j=0;  // 用于计数
	// 寻找要插入的位置
	while(p->next&&j<i)
	{
		p=p->next;  // 移动p到下一个结点
		j++;  // 计数加一
	}
	if(j<i)  // 如果i超过了链表长度,则返回错误
	{
		return 0;
	}
	DLNode *s;  // 创建新结点
	s=(DLNode*)malloc(sizeof(DLNode));
	s->data=e;  // 设置新结点的数据
	one;  // 更新新结点的前驱
	two;  // 更新原p的前驱的后继
	three;  // 更新新结点的后继
	four;  // 更新p的前驱
	return 1;  // 返回成功标志
}

// 打印双链表的所有元素
void printElem(DLinkList head)
{
	DLNode *p;
	p=head->next;  // 从第一个实际数据结点开始
	while(p)
	{
		printf("%d ",p->data);  // 打印当前结点的数据
		p=p->next;  // 移动到下一个结点
	}
	printf("\n");  // 打印换行符
}

上述案例的运行结果:

结果表明可以将40这个数据正确的插入30的后面

这里注意我为了探究插入顺序定义的宏:

// 宏定义简化了插入操作中的四个关键步骤
#define one s->prior=p->prior  // 新节点s的前驱指向p的前驱
#define two p->prior->next=s    // p的前驱的后继指向新节点s
#define three s->next=p         // 新节点s的后继指向p
#define four p->prior=s         // p的前驱指向新节点s

这4步画出来如图所示:

这个顺序像是在空中画一个躺下来的数字8一样,方便记忆,这个顺序我们在明天的p后面插入同样这样记忆

上面的例子的顺序是1234,运行结果表明可以正确的插入。

如果顺序换成1423呢?结果会是怎么样? 

下面我们看这种情况的运行结果 :

可以发现没有将40正确的插入链表当中,也就是1423这个顺序不可行。

二、分析为什么1234可以,而1423不可以呢? 

        如果你可以充分理解这里的原因,那么剩下的22中情况,以及明天的24种后端插入的情况将迎刃而解!

我们先观察顺序,原来的顺序是1234

我只是把4放在了2前面,

变成了1423

为什么就插入失败了呢?

既然只动了2和4的位置,那我们就重点关注2和4分别是什么操作

2是p->prior->next=s,也就是p指向的前一个节点的下一个节点指向s,

4是p->prior=s,也就是p指向的前一个节点。

 1234这个顺序,2在前面,4在后面,也就是先执行2这个操作,将p的前驱指向s,然后再改变p的前驱成为s

1423这个顺序,4在前面,2在后面,也就是先执行4这个操作,先改变p的前驱成为s,然后再让p的前驱指向s

仔细思考这句话,既然你都将p的前驱变成s了,你还能让p的前驱指向s吗?当然不可以,这不是妥妥的s自己指向自己了吗?

如果自然语言描述不懂,我们来看先4后2的代码

我们看42这个顺序的代码

p->prior=s;

p->prior->next=s;

这不是翻译过来就是s->next=s吗

那么先执行4再执行2,这样就造成了p的真正前驱丢失,就不能让p的前驱正确的指向s啦(*^▽^*)

注意:这只会造成p的前驱丢失,并不会影响p的真正前驱指向p哦^_^,也就是我们可以正常输出原来的链表10 20 30 50 60 70 80 90

三、下面我们给出正确的12种情况的顺序,以及12种错误顺序

正确顺序:1234,1243,1324,2134,2143,2314,2341,2413,2431,3124,3214,3241

错误顺序:1342,1423,1432,3142,3412,3421,4123,4132,4213,4231,4312,4321

        这24种情况是我一个一个输出检验过的,只有24种还是可以动手一一列举的,要是5!= 120我就还是让计算机完成吧o(╥﹏╥)o

我们找到答案以后还应该寻找规律,不总结我们很难记住这24种哪个对哪个错,我们总结的目的之一就是方便考试的时候可以快速的判断正确错误。

四、在考试中如何快速判断题目给出的顺序是否正确?

正确顺序:1234,1243,1324,2134,2143,2314,2341,2413,2431,3124,3214,3241

错误顺序:1342,1423,1432,3142,3412,3421,4123,4132,4213,4231,4312,4321

        我们仔细观察并寻找规律,发现它有极其高的对称性,首先正确的有12个,错误的有12个;其次1开头的有3个正确的,有3个错误的;2开头的全是正确的;3开头的又是3个正确3个错误;最后4开头的全是错误的。

        这只是我们初步观察发现的规律,只看这个结果发现的,那这感觉还是不好记呀,虽然比记住24种方便了一点,可是我在考试还得将代码转换成1234才能用这个规律,有没有更简单的方法呀!o(╥﹏╥)o

        当然有!找到最方便好记的规律我们就要结合《标题二:分析为什么1234可以,而1423不可以呢?》的原理,结合是什么原因造成的插入成功与失败,在《标题二》的分析中,我们知道这是2和4的位置顺序造成的,跟13没有关系,那我们现在观察一下结果中2和4的顺序是怎么影响结果的。

观察发现, 只要4在2的后面就是正确的,只要4在2的前面就不对

正确顺序:1234,1243,1324,2134,2143,2314,2341,2413,2431,3124,3214,3241(4在2后)

错误顺序:1342,1423,1432,3142,3412,3421,4123,4132,4213,4231,4312,4321(4在2前)

也就是在考试中,我们只需要观察4和2的位置关系即可,

4在2后就是正确的,也就是p->prior=s在p->prior->next=s的后面就是正确的,

4在2前就是错误的,也就是p->prior=s在p->prior->next=s的前面就是错误的。

原因在就在《标题二》的分析中。

这样我们在考试中只用观察这两个操作的位置即可,只要13存在,就观察24位置就好啦O(∩_∩)O

五、结论

4在2后就是正确的,也就是p->prior=s在p->prior->next=s的后面就是正确的,

4在2前就是错误的,也就是p->prior=s在p->prior->next=s的前面就是错误的。

一定注意:该结论只适用于p指向待插入元素的后面,关于p指向待插入元素的前面的规律,我会在明天发文总结!!!     

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

构建高效服装销售平台:Spring Boot与“衣依”案例

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

hystrix微服务部署

目录 一.启动nacos和redis 1.查看是否有nacos和redis 二.开始项目 1.hystrix1工程&#xff08;修改一下工程的注册名字&#xff09; 2.运行登录nacos网站查看运行效果&#xff08;默认密码nacos,nacos&#xff09; 3.开启第二个项目 hystrix2工程 4.关闭第二个项目 hyst…

UE4 材质学习笔记02(数据类型/扭曲着色器)

一.什么是数据类型 首先为啥理解数据类型是很重要的。一些节点的接口插槽只接受特定类型的数据&#xff0c;如果连接了不匹配的数据就会出现错误&#xff0c;有些接口可以接受任何数据类型&#xff0c;但是实际上只会使用到其中的一些。并且有时可以将多个数据流合并成一个来编…

选择排序:直接选择排序、堆排序

目录 直接选择排序 1.选择排序的基本思想 2.直接选择排序的基本思想 3.直接插入排序的代码思路步骤 4.直接选择排序代码 5.直接选择排序的特性总结 堆排序 一、排升序&#xff0c;建大堆 1.利用向上调整函数建大堆 1.1.建立大堆的思路 1.2.以下是具体步骤&#xff1a…

【人人保-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

C++系列-多态

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 多态 多态就是不同类型的对象&#xff0c;去做同一个行为&#xff0c;但是产生的结果是不同的。 比如说&#xff1a; 都是动物叫声&#xff0c;猫是喵喵&#xff0c;狗是汪汪&am…

Flink集群部署

本次部署1.17版本 需要修改的配置文件地方为 Job为指挥中心&#xff0c;只能有一台主机&#xff0c;集群中所有的配置文件都这样配置 Rest为客户端UI显示使用&#xff0c;集群中所有的配置文件都这样配置 Task是每个节点工作使用的&#xff0c;每个节点的Task各不相同 conf配…

【mmengine】配置器(config)(进阶)继承与导出,命令行修改配置

一、配置文件的继承 1.1 继承机制概述 新建optimizer_cfg.py: optimizer dict(typeSGD, lr0.02, momentum0.9, weight_decay0.0001)新建runtime_cfg.py: device "cuda" gpu_ids [0, 1] batch_size 64 epochs 100 num_workers 8新建resnet50.py: _base_ […

数据结构-3.9.栈在递归中的应用

一.函数被调用背后的过程&#xff1a;最后被调用的函数最先结束也符合栈的后进先出 1.main函数为主函数即程序入口&#xff0c;运行时主函数先入栈&#xff0c;然后存入主函数里的数据&#xff1b; 2.func1函数加载在栈中时他后面的代码的地址#1(调用返回地址&#xff0c;不是…

OpenAI全新多模态内容审核模型上线:基于 GPT-4o,可检测文本和图像

在数字时代&#xff0c;内容安全问题愈发受到重视。9月26日&#xff0c;OpenAI 正式推出了一款全新的多模态内容审核模型&#xff0c;名为 “omni-moderation-latest”。 该模型基于最新的 GPT-4o 技术&#xff0c;能够准确地识别检测有害文本图像。这一更新将为开发者提供强大…

Woocommerce怎么分类显示产品?如何将Shopify的产品导入到Woocommerce?

WooCommerce作为WordPress的一个电子商务插件&#xff0c;功能强大、使用简洁&#xff0c;能够轻松集成到WordPress网站中&#xff0c;为用户提供了一个完整的在线商店解决方案&#xff0c;在国外还是挺受欢迎的。 Woocommerce怎么分类显示产品&#xff1f; 在Woocommerce中&a…

TCP Analysis Flags 之 TCP ZeroWindowProbe

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…

【C++】空指针和野指针

文章目录 1.空指针2.野指针总结 1.空指针 概念&#xff1a;指针变量指向内存中编号为0的空间。 用途&#xff1a;初始化指针变量。 注意&#xff1a;空指针指向的内存是不可以访问的。 示例&#xff1a; int main(){//指针变量p指向内存地址编号为0的空间int *PNULL&#…

在java后端发送HTTPClient请求

简介 HttpClient遵循http协议的客户端编程工具包支持最新的http协议 部分依赖自动传递依赖了HttpClient的jar包 明明项目中没有引入 HttpClient 的Maven坐标&#xff0c;但是却可以直接使用HttpClient原因是&#xff1a;阿里云的sdk依赖中传递依赖了HttpClient的jar包 发送get请…

Django 配置邮箱服务,实现发送信息到指定邮箱

一、这里以qq邮箱为例&#xff0c;打开qq邮箱的SMTP服务 二、django项目目录设置setting.py 文件 setting.py 添加如下内容&#xff1a; # 发送邮件相关配置 EMAIL_BACKEND django.core.mail.backends.smtp.EmailBackend EMAIL_USE_TLS True EMAIL_HOST smtp.qq.com EMAIL…

1.2.2 计算机网络的分层结构(下)

水平视角 YSCS协议&#xff08;压缩传输协议&#xff09; 发送方先压缩然后接收方再解压。 为什么要分层&#xff1f;为什么要制定协议&#xff1f; 计算机网路功能负责->采用分层结构&#xff0c;将诸多功能合理地划分在不同层次->对等层之间制定协议&#xff0c;以…

正则表达式的使用示例--Everything文件检索批量重命名工具

一、引言 Everything是一款非常实用的文件搜索工具&#xff0c;它可以帮助您快速定位并查找计算机中的文件和文件夹。Everything搜索文件资料之神速&#xff0c;有使用过的朋友们都深有体会&#xff0c;相对于Windows自带的搜索功能&#xff0c;使用Everything&#xff0c;可以…

QT将QBytearray的data()指针赋值给结构体指针变量后数据不正确的问题

1、问题代码 #include <QCoreApplication>#pragma pack(push, 1) typedef struct {int a; // 4字节float b; // 4字节char c; // 1字节int *d; // 8字节 }testStruct; #pragma pack(pop)#include <QByteArray> #include <QDebug>int main() {testStruct …

基于VUE的在线手办交易平台购物网站前后端分离系统设计与实现

目录 1. 需求分析 2. 技术选型 3. 系统架构设计 4. 前端开发 5. 后端开发 6. 数据库设计 7. 测试 8. 部署上线 9. 运维监控 随着二次元文化的兴起&#xff0c;手办作为一种重要的周边产品&#xff0c;受到了广大动漫爱好者的喜爱。手办市场的需求日益增长&#xff0c;…

Android-Handle消息传递和线程通信

本文为作者学习笔记&#xff0c;如有误&#xff0c;请各位大佬指点 目录 一、同步异步 二、Java多线程通信 三、Handler是什么 四、Handler相关的类 五、Handler常用方法 1. 发送消息 2. 接收处理消息 3. 切换线程 六、使用Handler 使用Handler更新UI 使用Handler延…