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

news2024/10/5 2:47:40

 

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

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

  

前言:

        在学习数据结构与算法的课程中,单链表的插入操作只用操作两个指针就可以完成操作,因为单链表就一个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指向待插入元素的前面的规律,我会在明天发文总结!!!     

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

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

相关文章

一次解决Go编译问题的经过

用Go语言编写了一个小的项目&#xff0c;项目开发环境是在本地的Windows环境中&#xff0c;一切单元测试和集成测试通过后&#xff0c;计划将项目部署到VPS服务器上自动运行&#xff0c;但在服务器上执行go run运行时&#xff0c;程序没有任何响应和回显&#xff0c;甚至main函…

有没有一款软件,可以在二楼电脑直接唤醒三楼的电脑?

前言 今天有个小姐姐找到我&#xff0c;咨询能不能在二楼的电脑直接访问到三楼电脑的资料。 这个肯定是可以的啊&#xff01; 其实事情很简单&#xff0c;只需要弄好共享文件夹这个功能&#xff0c;只要手机、平板或者电脑在同个局域网下&#xff0c;就能访问到三楼电脑里的…

深入理解Dubbo源码核心原理-Part4

现在开始研究&#xff0c;消费端真正调用proxy的方法时&#xff0c;走的rpc调用 接下来就要走client&#xff0c;发送request请求了 Dubbo协议是怎样的呢&#xff1f; 具体每个字段什么含义请参照官网 链接&#xff1a;Dubbo协议头含义 编码器按照Dubbo协议来进行编码请求 Ne…

JVM内存回收机制

目录 1.JVM运行时数据区 2.JVM类加载过程 3.双清委派模型 4.垃圾回收机制&#xff08;GC&#xff09; 找出谁是垃圾方案一&#xff1a;引用计数 找出谁是垃圾&#xff1a;方案二&#xff0c;可达性分析 释放垃圾的内存空间 判断垃圾&#xff1a;jvm依据对象的年龄对 对象…

基于Zynq SDIO WiFi移植三(支持2.4/5G)

应用问题-WIFI作为AP-hostapd多次连接 设备作为WIFI热点时&#xff0c;连接出现了下述问题&#xff1a; 1 手机连接需要三次&#xff0c;三次都需要输入密码&#xff1b; 2 平板连接需要三次&#xff0c;三次都需要输入密码&#xff1b; 3 电脑连接需要一次&#xff0c;无感…

隧道人员定位UWB双通道定位终端

大家好&#xff0c;我是华星智控小智&#xff0c;今天我给大家介绍我们的UWB双通道定位终端。 双通道定位终端&#xff08;型号STD&#xff09;主要用于隧道人员或天车定位&#xff0c;终端基于无线脉冲技术&#xff0c;采用双天线设计&#xff0c;可实现对2路方向的测距定位&a…

实施威胁暴露管理、降低网络风险暴露的最佳实践

随着传统漏洞管理的发展&#xff0c;TEM 解决了因攻击面扩大和安全工具分散而产生的巨大风险。 主动式 TEM 方法优先考虑风险并与现有安全工具无缝集成&#xff0c;使组织能够在威胁被有效利用之前缓解威胁。 为什么威胁暴露管理 (TEM) 在现代网络安全策略中变得至关重要&…

使用模拟和真实的 Elasticsearch 来测试你的 Java 代码

作者&#xff1a;来自 Elastic Piotr Przybyl 在本文中&#xff0c;我们将介绍并解释两种使用 Elasticsearch 作为外部系统依赖项来测试软件的方法。我们将介绍使用模拟测试和集成测试的测试&#xff0c;展示它们之间的一些实际差异&#xff0c;并给出一些关于每种风格的提示。…

嵌入式C语言自我修养:编译链接

源文件生成可执行文件的过程&#xff1f; 源文件经过预处理、编译、汇编、链接生成一个可执行的目标文件。 编译器驱动程序&#xff0c;包括预处理器、编译器、汇编器和链接器。Linux用户可以调用GCC驱动程序来完成整个编译流程。 使用GCC驱动程序将示例程序从ASCII码源文件转换…

如何使用EventChannel

文章目录 1 知识回顾2 示例代码3 经验总结我们在上一章回中介绍了MethodChannel的使用方法,本章回中将介绍EventChannel的使用方法.闲话休提,让我们一起Talk Flutter吧。 1 知识回顾 我们在前面章回中介绍了通道的概念和作用,并且提到了通道有不同的类型,本章回将其中一种…

仿RabbitMQ实现消息队列服务端(一)

文章目录 交换机数据管理队列数据管理绑定信息(交换机-队列)管理队列消息管理虚拟机管理交换机路由管理队列消费者/订阅者管理 整体框架&#xff1a;工具模块及项目整体模块框架 交换机数据管理 交换机数据管理就是描述了交换机应该有哪些数据 定义交换机数据类 1、交换机的名…

Linux忘记root用户密码怎么重设密码

直接说步骤&#xff1a; 1.重启客户机 2.在选择内核页面快速按e键&#xff0c;进入编辑模式 进入后应该是这个样子 在这里只能按上下键切换行 找到Linux16这里 3.按右方向键切换到行尾&#xff0c;也就是UTF-8处&#xff0c;在后面添加一个空格&#xff0c;然后加上这段话 …

鸿蒙网络管理模块04——网络连接管理

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 网络连接管理提供管理网络一些基础能力&#xff0c;包括WiFi/蜂窝/Etherne…

数据库概述(1)

课程主页&#xff1a;Guoliang Li Tsinghua 数据库在计算机系统中的位置 首先&#xff0c;数据库是在设计有大量数据存储需求的软件时必不可少可的基础。 最常见的是&#xff1a;我们通过app或者是浏览器来实现一些特定需求——比如转账、订车票。即引出背后的CS和BS两种网…

如何用深度神经网络预测潜在消费者

1. 模型架构 本项目采用的是DeepFM模型&#xff0c;其结构结合了FM&#xff08;因子分解机&#xff09;与深度神经网络&#xff08;DNN&#xff09;&#xff0c;实现了低阶与高阶特征交互的有效建模。模型分为以下几层&#xff1a; 1.1 FM部分&#xff08;因子分解机层&#…

Epoch、Batch与Iteration简答理解

揭秘神经网络训练的三大神秘要素:Epoch、Batch与Iteration 在探索深度学习的奇妙世界时,你是否曾被Epoch、Batch和Iteration这三个术语搞得晕头转向?别担心,今天我们就来揭开它们的神秘面纱,带你深入了解神经网络训练的奥秘! 一、Epoch:时间的轮回,数据的洗礼 Epoch…

Python | Leetcode Python题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution:def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:countAB collections.Counter(u v for u in A for v in B)ans 0for u in C:for v in D:if -u - v in countAB:ans countAB…

《深度学习》OpenCV 图像拼接 原理、参数解析、案例实现

目录 一、图像拼接 1、直接看案例 图1与图2展示&#xff1a; 合并完结果&#xff1a; 2、什么是图像拼接 3、图像拼接步骤 1&#xff09;加载图像 2&#xff09;特征点检测与描述 3&#xff09;特征点匹配 4&#xff09;图像配准 5&#xff09;图像变换和拼接 6&am…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-03

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-03 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-03目录1. A Scalable Data-Driven Framework for Systematic Analysis of SEC 10-K Filings Using Large Language Models摘要研…

centos72009源码编译R语言

./dev/make-distribution.sh --name custom-spark --pip --r --tgz -Pconnect -Psparkr -Phive -Phive-thriftserver -Pmesos -Pyarn -Dhadoop.version3.4.0 -Pkubernetes spark3.5.3 源码版本 ./dev/make-distribution.sh --name custom-spark --pip --r --tgz -Pconnect -P…