深入探究:在双链表指定元素的后面进行插入操作的顺序

  

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

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

前言:

        昨天,我们探究了在双链表指定元素的前面进行插入操作的顺序,并总结了方便记忆的规律今天我们继续探究在后面插入的顺序规律,并且将今天的规律与昨天的作对比,综合起来,找到相同之处与不同所在,这会让我们对双链表底层原理理解的更加深入,在考试当中可以快速给出正确优美的答案。         

        注意:本章节讲的是在p指向待插入元素的前面,所以后面讲的结论只适用于往p指向的结点后面插入一个元素,关于p指向待插入元素的后面的规律,请参考上一篇博文!!!

一、代码部分与昨天一样,只改变了宏的定义

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

// 定义数据类型为整型
#define DataType int
// 定义一个简单的调试宏,用于输出整数
#define debug(a) printf("%d ",a)

// 下面四个宏定义了插入节点时需要执行的操作
#define one s->prior=p       // 设置新节点s的前驱指针指向p
#define two p->next=s        // 将p的后继指针指向新节点s
#define three s->next=p->next // 设置新节点s的后继指针指向p的下一个节点
#define four p->next->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);
//逆序打印双向链表中的所有元素
void rprintElem(DLinkList head);

int main()
{	
    // 初始化数组
    int a[10] = {10,20,30,50,60,70,80,90};
    DLinkList L;
    // 初始化链表
    InitDLinkList(&L);
    // 使用数组创建链表
    CreatDLinkList(L, a);
    // 打印链表
    printElem(L);
    // 在第3个位置后面插入40
    InsertElem(L, 3, 40);
	printf("插入元素后,从前往后遍历:\n");
    // 再次打印链表以验证插入操作
    printElem(L);
	printf("插入元素后,从后往前遍历:\n");
    rprintElem(L);
    return 0;
} 

// 初始化链表头结点,并设置其next指针为空
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++)
    {
        s = (DLNode*)malloc(sizeof(DLNode));  // 分配新结点
        s->data = a[i];  // 设置新结点的数据
        p->next = s;  // 链接新结点到当前p之后
        s->prior = 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;
        j++;
    }
    if (j < i)
    {
        return 0;  // 如果未找到正确的位置,则返回失败
    }
    DLNode *s;
    s = (DLNode*)malloc(sizeof(DLNode));
    s->data = e;  // 设置新结点的数据
    one;  two;  three;  four;  // 使用宏指令完成新结点的链接
    return 1;  // 返回成功
}

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

        代码部分相比昨天只改变了宏的部分,因为只需要把p指向前一个元素,宏定义改成后端插入元素的操作即可,为了第一次看这篇博文的人方便,我还是把代码全部展示上吧。^_^

        重点关注宏定义以及插入的顺序

宏定义: 

#define one s->prior=p       // 设置新节点s的前驱指针指向p
#define two p->next=s        // 将p的后继指针指向新节点s
#define three s->next=p->next // 设置新节点s的后继指针指向p的下一个节点
#define four p->next->prior=s // 如果p后面有节点,则更新该节点的前驱指针为s

上述案例的插入顺序:

这里给出图像便于理解:

 我们还用昨天的顺序,方便记忆,像在空中画一个躺下来的数字8

下面我们看该顺序1234的运行结果:

        什么!!!竟然没有将40正确的插入30的后面,输出是一个死循环,为什么昨天1234的顺序可以正确的插入50的前面呢???我这里只让p指向了待插入元素的前面

        我们改变一下顺序,变成1324顺序,再运行一下,观察结果如何,只调换2和3的位置。

我们看运行结果: 

上面的两个例子表明1234和1324都不可行。

我们再把2放在最后面成1342,观察结果:

结果表明1342可以正确插入。 

二、分析为什么1234和1324不可以,而1342可行呢?

        这个问题与昨天极其相似,我们直接顺着昨天的思路,观察先2后3还有先2后4为什么不行?

我们给出先2后3的代码部分:

p->next=s;

s->next=p->next;

这两步合起来不就是s->next=s吗,和昨天的错误一样,都是s自己指向了自己,但是昨天并不影响输出原链表,因为只是找不到正确的前驱了,但是这个会影响输出原来的链表,因为这个找不到正确的后继了,从前往后遍历会因为s形成了环而找不到双链表的尾结点,造成一直输出s里面保存的数据。

我们在给出先2后4的代码:

p->next=s;

p->next->prior=s

合并一下就是s->prior=s,错误很明显了

        只要充分理解昨天《标题二》的内容,这里我相信会很容易的。 

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

四、总结规律 

有了昨天的经验,我们直接看2关于3和4的位置

发现

2只要在3和4的后面就是正确的,

2只要在3前面或者4前面就是错误的

五、我们来一道考研真题练练手

4-4.设双向循环链表中结点的结构有数据域 data,指针域 pre和next,链表不带头结点。若在指针 p所指结点之后插入结点 s,则应执行下列( )操作。【南京理工大学 2005 一、3(1分)】【北京交通大学 2006 一、1(2 分)】
A.p->next=s; s->pre=p;p->next->pre=s; s->next=p->next;
B.p->next=s; p->next->pre=s; s->pre=p; s->next=p->next;
C.s->pre=p; s->next=p->next; p->next=s; p->next->pre=s;
D.s->pre=p; s->next =p->next; p->next->pre=s; p->next=s;

有了结论可以快速标序号找到答案,就是D

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

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

相关文章

Win10系统插入带有麦克风的耳机_麦克风不起作用_解决方法_亲测成功---Windows运维工作笔记054

今天我在使用讯飞输入法的时候,想通过讯飞的语音输入法来提高自己的输入效率。 但是这个时候发现一个问题就是我插入我的台式机的是一个带有麦克风的耳机。 但是发现我这个耳机没有办法被电脑识别出麦克风来,所以说就没办法使用讯飞输入法的语音输入功能来直接输入文字了。…

【重学 MySQL】五十六、位类型

【重学 MySQL】五十六、位类型 定义赋值与使用注意事项应用场景 在MySQL数据库中&#xff0c;位类型&#xff08;BIT类型&#xff09;是一种用于存储位字段值的数据类型。 定义 BIT(n)表示n个位字段值&#xff0c;其中n是一个范围从1到64的整数。这意味着你可以存储从1位到64…

华为GaussDB数据库之Yukon安装与使用

一、Yukon简介 Yukon&#xff08;禹贡&#xff09;&#xff0c;基于openGauss、PostgreSQL、GaussDB数据库扩展地理空间数据的存储和管理能力&#xff0c;提供专业的GIS&#xff08;Geographic Information System&#xff09;功能&#xff0c;赋能传统关系型数据库。 Yukon 支…

论文笔记(四十七)Diffusion Policy: Visuomotor Policy

Diffusion Policy: Visuomotor Policy 文章概括摘要1. 介绍2. 扩散策略的公式化2.1 去噪扩散概率模型2.2 DDPM 训练2.3 用于视觉运动策略学习的扩散模型 3 关键设计决策3.1 网络架构选项3.2 视觉编码器3.3 噪声计划3.4 加速实时控制的推理 4. 扩散策略的四个引人入胜的特性4.1 …

回归预测 | Matlab基于SABO-SVR减法平均算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于SABO-SVR减法平均算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于SABO-SVR减法平均算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于SABO-SVR减法平均算法优化…

【api连接ChatGPT的最简单方式】

通过api连接ChatGPT的最简单方式 建立client 其中base_url为代理&#xff0c;若连接官网可省略&#xff1b;配置环境变量 from openai import OpenAI client OpenAI(base_url"https://api.chatanywhere.tech/v1" )或给出api和base_url client OpenAI(api_key&…

数据仓库简介(一)

数据仓库概述 1. 什么是数据仓库&#xff1f; 数据仓库&#xff08;Data Warehouse&#xff0c;简称 DW&#xff09;是由 Bill Inmon 于 1990 年提出的一种用于数据分析和挖掘的系统。它的主要目标是通过分析和挖掘数据&#xff0c;为不同层级的决策提供支持&#xff0c;构成…

wordpress源码资源站整站打包32GB数据,含6.7W条资源数据

源码太大了&#xff0c;足足32gb&#xff0c;先分享给大家。新手建立资源站&#xff0c;直接用这个代码部署一下&#xff0c;数据就够用了。辅助简单做下seo&#xff0c;一个新站就OK了。 温馨提示&#xff1a;必须按照顺序安装 代码下载

【word脚注】双栏设置word脚注,脚注仅位于左栏,右栏不留白

【word脚注】双栏设置word脚注&#xff0c;脚注仅位于左栏&#xff0c;右栏不留白 调整前效果解决方法调整后效果参考文献 调整前效果 调整前&#xff1a;脚注位于左下角&#xff0c;但右栏与左栏内容对其&#xff0c;未填充右下角的空白区域 解决方法 备份源文件复制脚注内…

【HTML|第1期】HTML5视频(Video)元素详解:从起源到应用

日期&#xff1a;2024年9月9日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉在这里插入代码片得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对…

【机器学习】探索GRU:深度学习中门控循环单元的魅力

目录 &#x1f354; GRU介绍 &#x1f354; GRU的内部结构图 2.1 GRU结构分析 2.2 GRU工作原理 2.4 Bi-GRU介绍 2.3 使用Pytorch构建GRU模型 2.5 GRU优缺点 &#x1f354; 小结 学习目标 &#x1f340; 了解GRU内部结构及计算公式. &#x1f340; 掌握Pytorch中GRU工具…

MySQL--数据库约束(详解)

目录 一、前言二、概念三、数据库约束3.1 约束类型3.1.1 NOT NULL 约束3.1.2 UNIQUE (唯一&#xff09;3.1.3 DEFAULT&#xff08;默认&#xff09;3.1.4 PRIMARY KEY&#xff08;主键&#xff09;3.1.5 FOREIGN KEY&#xff08;外键&#xff09;3.1.6 CHECK 四、总结 一、前言…

[Linux#61][UDP] port | netstat | udp缓冲区 | stm32

目录 0. 预备知识 1. 端口号的划分范围 2. 认识知名端口号 3. netstat 命令 4. pidof 命令 二.UDP 0.协议的学习思路 1. UDP 协议报文格式 报头与端口映射&#xff1a; 2. UDP 的特点 面向数据报&#xff1a; 3. UDP 的缓冲区 4. UDP 使用注意事项 5. 基于 UDP 的…

基于Keras的U-Net模型在图像分割与计数中的应用

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&a…

11. 异步编程

计算机的核心部分&#xff0c;即执行构成我们程序的各个步骤的部分&#xff0c;称为处理器。我们迄今为止看到的程序都会让处理器忙个不停&#xff0c;直到它们完成工作。像操作数字的循环这样的程序的执行速度几乎完全取决于计算机处理器和内存的速度。但是&#xff0c;许多程…

相机基础概念

景深&#xff1a; 景深的定义 DOF:depth of filed 是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。光圈、镜头、及焦平面到拍摄物的距离是影响景深的重要因素。定义3&#xff1a;在镜头前方&#xff08;焦点的前、后&#xff09;有一…

螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下docker学习02(yum源切换及docker安装配置)

2 前期工作 2.1 切换yum源并更新 删除/etc/yum.repos.d/原有repo文件&#xff0c;将Centos-7.repo库文件拷贝到该目录下。 然后清楚原有缓存yum clean all 生成新的缓存yum makecache 更新yum update –y 然后再确认/etc/yum.repos.d/不会有其他库文件&#xff0c;只留下…

气象大模型天气预测对物流的影响

随着科技的进步&#xff0c;气象大模型&#xff08;GFM, Global Forecast Model&#xff09;的广泛应用大大提升了天气预测的精度和时效性。这些模型基于大数据、机器学习、人工智能等技术&#xff0c;能够模拟大气环流&#xff0c;预测未来的天气状况。对于物流行业而言&#…

Pikachu-暴力破解-验证码绕过(on client)

访问页面&#xff0c; 从burpsuite 上看到返回的源代码&#xff1b; 验证码生成时通过 createCode 方法生成&#xff0c;在前端页面生成&#xff1b; 同时也是在前端做的校验&#xff1b; 直接验证&#xff1b;F12 -- 网络&#xff0c;随便输入个账号、密码、验证码&#xff0…

C初阶(八)选择结构(分支结构)--if、else、switch

前言&#xff1a; C语言是用来解决问题的&#xff0c;除了必要的数据输入与输出&#xff08;见前文&#xff09;&#xff0c;还要有逻辑结构。其中基本可以归为三类&#xff1a;顺序结构、选择结构、循环结构。今天&#xff0c;杰哥提笔写的是关于选择结构&#xff08;又叫“分…