当前位置: 首页 > news >正文

链表中插入新的节点

/* 节点结构体定义 */
struct xLIST_ITEM
{TickType_t xItemValue;             /* 辅助值,用于帮助节点做顺序排列 */			struct xLIST_ITEM *  pxNext;       /* 指向链表下一个节点 */		struct xLIST_ITEM *  pxPrevious;   /* 指向链表前一个节点 */	void * pvOwner;					   /* 指向拥有该节点的内核对象,通常是TCB */void *  pvContainer;		       /* 指向该节点所在的链表 */
};
typedef struct xLIST_ITEM ListItem_t;  /* 节点数据类型重定义 */
/* 链表结构体定义 */
typedef struct xLIST
{UBaseType_t    uxNumberOfItems;    /* 链表节点计数器 */ListItem_t *   pxIndex;			/* 链表节点索引指针 */MiniListItem_t xListEnd;		/* 链表最后一个节点 */
} List_t;
/* 将节点插入到链表的尾部 */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{ListItem_t * const pxIndex = pxList->pxIndex;pxNewListItem->pxNext = pxIndex;                        //1pxNewListItem->pxPrevious = pxIndex->pxPrevious;        //2pxIndex->pxPrevious->pxNext = pxNewListItem;            //3pxIndex->pxPrevious = pxNewListItem;                    //4/* 记住该节点所在的链表 */pxNewListItem->pvContainer = ( void * ) pxList;         //5/* 链表节点计数器++ */( pxList->uxNumberOfItems )++;                          //6
}

学习过“野火”freeRTOS的童鞋们一定会对这些代码眼熟,我刚学,只是发表一下个人的观点和见解,大神可以直接跳过,写的理解可能只适用于刚接触链表有关知识点的小伙伴,不敢说通俗易懂,但是对于我本身这种菜鸟很容易接受和理解。重点讲解一下第三段代码的逻辑!!!!不喜欢可以敬请喷,我会及时当勉励的。

初始链表结构

假设链表当前结构如下(以便于理解,假设链表已有两个有效节点 AB),并且 pxIndex 是伪头节点,它指向链表的末尾:

NULL <- A <-> B <-> pxIndex -> NULL

我们可以将链表节点看成是互相握手的小人,他们按照一定的顺序排列。我们一步步看看新小人 C 是如何加入到一群已经排好队的小人 AB 和尾巴节点 pxIndex 中的。

初始状态

假设我们有一个双向链表队伍,它的排列如下:

A <-> B <-> pxIndex

这里的每个箭头 <-> 表示一个节点和它相邻节点之间的双向关系。pxIndex 可以看作是一个站在队伍最后的标记节点,不是真正的队伍成员。

  • A:队伍中的第一个小人,没有人站在他前面。
  • B:A 后面的一个小人。
  • pxIndex:一个标记队伍末尾的小人,没有其他人站在他后面。

此时,队伍中的人数为 2(A 和 B),由变量 pxList->uxNumberOfItems 记录。

目标

现在,我们想让小人 C 加入队伍,站在 BpxIndex 之间。最终目标是让队伍变成:

A <-> B <-> C <-> pxIndex

插入过程一步步拆解

1. 让 C 知道他后面是谁

代码的第一步是让 CpxNext 指针指向 pxIndex,也就是告诉 C 站在他后面的是 pxIndex

pxNewListItem->pxNext = pxIndex;

现在 CpxNext 指针指向了 pxIndex,表示他知道了自己后面是队伍的尾巴节点。

A <-> B     C -> pxIndex
2. 让 C 知道他前面是谁

接下来,我们需要告诉 C 站在他前面的是 B。我们通过 pxIndex->pxPrevious 找到 B,然后把 B 的地址赋给 CpxPrevious 指针:

pxNewListItem->pxPrevious = pxIndex->pxPrevious;

现在 CpxPrevious 指针指向了 B,表示 C 知道了他前面是谁。

A <-> B <-> C -> pxIndex
3. 让 B 知道他后面多了一个人

在队伍中,双向链表是彼此双向连接的。所以我们还需要告诉 B,让他知道后面站了一个新小人 C。我们通过 pxIndex->pxPrevious->pxNext 找到 BpxNext,然后把 C 的地址赋给它:

pxIndex->pxPrevious->pxNext = pxNewListItem;

这样 BpxNext 指针指向了 C,表示 B 知道他后面站了一个新成员 C

A <-> B <-> C -> pxIndex
4. 更新队尾指针,表示 C 是最后一个人

队尾指针 pxIndex->pxPrevious 需要指向新插入的节点 C,表示队伍的最后一个有效成员是 C。因此,pxIndex->pxPrevious = pxNewListItem;

pxIndex->pxPrevious = pxNewListItem;

现在 pxIndex->pxPrevious 指向了 C,表示 C 成为新的尾巴前的最后一个节点。

A <-> B <-> C <-> pxIndex
5. 记录新节点 C 的所属链表

我们把 pxList 的地址存储在 C->pvContainer 中,方便以后找到 C 属于哪个链表:

pxNewListItem->pvContainer = ( void * ) pxList;
6. 更新链表节点计数器

最后,链表节点数量增加了 1:

( pxList->uxNumberOfItems )++;

现在链表计数器变成了 3,准确记录了链表中有 ABC 三个节点。

总结

整个过程简单来说,就是让新节点 C 找到他前后的人,同时告诉他前后的人有了新成员 C,最后更新链表的头尾标记和计数器。

看到这里,你是不是已经完全理解和消化掉了如何插入新节点呢?会不会有一点点疑问,但是又不好意思问呢?我自我提问几个问题吧,因为太菜因为c学的不到位,所以就问题多多了一些。

Question One:

为什么pxIndex->pxPrevious代表的是B?????

答:

在这个链表结构中,pxIndex 是一个伪尾节点(或称标记节点),它作为链表的终点标记。因为 pxIndex 并不是真正的有效数据节点,它的作用只是指示链表的尾部。链表中的实际有效节点依次连接,而 pxIndex 在链表结构上只是方便操作的一个标记。

让我们来看看为什么 pxIndex->pxPrevious 会代表链表的最后一个有效节点 B

伪尾节点(pxIndex)的工作方式

在这个双向链表中:

  • pxIndex 总是指向链表的尾部,并且它的 pxNext 通常指向 NULL 或自己,以表示链表的终止。
  • pxIndex->pxPrevious 是链表最后一个有效节点。这是因为链表的逻辑结构让 pxIndex 成为尾节点标记,那么它的 pxPrevious 指针自然指向链表中真正的最后一个有效节点。

当前链表的结构示例

假设链表中有两个有效节点 AB,链表的结构如下:

NULL <- A <-> B <-> pxIndex

在这个结构中:

  • A 是链表的第一个有效节点,所以 A->pxPreviousNULL
  • B 是链表中最后一个有效节点,所以 B->pxNext 指向 pxIndex
  • pxIndex 是链表的伪尾节点,所以 pxIndex->pxPrevious 指向 B

插入新节点的操作

当我们向链表末尾插入新节点 C 时,步骤如下:

  1. 新节点 CpxPrevious 被设置为当前最后一个有效节点,即 pxIndex->pxPrevious,也就是 B
  2. B->pxNext 被更新为 C,表示 B 的后面现在是 C
  3. pxIndex->pxPrevious 更新为 C,表示 C 成为链表中的新最后一个有效节点。

最终,链表结构变为:

NULL <- A <-> B <-> C <-> pxIndex

小结

因此,pxIndex->pxPrevious 总是指向链表的最后一个有效节点。这是因为 pxIndex 是一个伪尾节点,它自己没有有效数据,只是标记链表的终点。

Question Two:

pxIndex->pxPrevious->pxNext = pxNewListItem;为什么pxNewListItem是c的地址,pxNewListItem不是包括C的next和previous嘛?

答:

在这段代码中,pxNewListItem 是一个指向新节点的指针,表示整个新节点 C 的地址。这个指针本身包含了新节点的所有信息,包括它的 pxNextpxPrevious 指针。

当我们写 pxIndex->pxPrevious->pxNext = pxNewListItem; 时,我们在做的实际上是更新链表中前一个节点的 pxNext 指针,使它指向新节点 C。这一步的关键在于理解双向链表节点之间的指针如何相互指向,并构成链表结构。

让我们深入理解一下这里的具体含义。

理解 pxNewListItem 的作用

  1. pxNewListItem 作为新节点的整体指针
    pxNewListItem 指向整个节点 C,即包含了 CpxNextpxPrevious 等信息。因此,pxNewListItem 并不是指向 C 的某个特定成员,而是指向节点 C 本身的起始地址

  2. 在链表中建立前后关系
    在链表中,每个节点的 pxNextpxPrevious 指针都用于指向相邻节点。这段代码:

pxIndex->pxPrevious->pxNext = pxNewListItem;
  1. 等效于 B->pxNext = pxNewListItem,其中 BpxIndex->pxPrevious 指向的最后一个有效节点。这一步就是让 B->pxNext 指向新节点 C 的整体地址(即 pxNewListItem),表示 B 的下一个节点现在是 C。通过这一指向关系的设置,BC 之间的链接建立起来了。

  2. 为什么是整个 C 的地址
    pxNewListItem 的确包含 CpxNextpxPrevious 指针,但在这行代码中,我们只关心将 pxNewListItem 作为一个完整的节点地址赋给 B->pxNext,表示 B 后面的节点是 CpxNextpxPrevious 的详细信息只有在访问节点 C 本身时才会被读取和使用。

代码工作流程小结

  1. pxNewListItem->pxNext = pxIndex;:将 C->pxNext 指向 pxIndex,表示 C 后面是伪尾节点 pxIndex
  2. pxNewListItem->pxPrevious = pxIndex->pxPrevious;:将 C->pxPrevious 指向 B(原最后一个节点)。
  3. pxIndex->pxPrevious->pxNext = pxNewListItem;:将 B->pxNext 指向 C,即 B 现在知道他后面是 C
  4. pxIndex->pxPrevious = pxNewListItem;:将 pxIndex->pxPrevious 更新为 C,即 C 成为新的最后一个有效节点。

总结

pxIndex->pxPrevious->pxNext = pxNewListItem; 中,pxNewListItem 表示整个新节点 C 的地址,而不只是它的 pxNextpxPrevious。我们通过这个赋值操作让 B->pxNext 指向 C 的地址,从而把 C 插入到 BpxIndex 之间。

相关文章:

链表中插入新的节点

/* 节点结构体定义 */ struct xLIST_ITEM {TickType_t xItemValue; /* 辅助值&#xff0c;用于帮助节点做顺序排列 */ struct xLIST_ITEM * pxNext; /* 指向链表下一个节点 */ struct xLIST_ITEM * pxPrevious; /* 指向链表前一个节点 */ void * pvOw…...

AUTOSAR从入门到精通-BswM模块(二)

目录 前言 算法原理 BswM接口端口 BswM功能描述 模式仲裁 仲裁规则(Arbitration Rules) 模式仲裁来源 模式仲裁过程 模式条件(ModeCondition) 逻辑表达式(LogicExpressions) 模式控制 模式处理 操作执行 模式控制过程 模式控制基本流程 BswM Interfaces and …...

Spring DispatcherServlet详解

文章目录 Spring DispatcherServlet详解一、引言二、DispatcherServlet的初始化与工作流程1、DispatcherServlet的初始化1.1、加载配置和建立WebApplicationContext1.2、初始化策略 2、DispatcherServlet的工作流程2.1、请求分发2.2、代码示例 三、总结 Spring DispatcherServl…...

JS | 软件制作的流程是什么?

目录 一、 需求分析 二、 系统设计 三、 编码实现 四、 测试验证 五、 部署上线 六、 维护更新 软件制作的流程主要包含需求分析、系统设计、编码实现、测试验证、部署上线和维护更新。其中&#xff0c;需求分析是基础&#xff0c;它决定了软件的功能和性能&#xff1b;通…...

简单工厂模式

引言 简单工厂模式并不属于23种设计模式&#xff0c;它是工厂方法模式的“小弟”&#xff0c;由于日常编程中大家会经常用到&#xff0c;只不过没有察觉&#xff0c;因此下文将详解简单工厂模式。 1.概念 简单工厂模式(Simple Factory Pattern)&#xff1a;又称为静态工厂方法(…...

【django】Django REST Framework 序列化与反序列化详解

目录 1、什么是序列化和反序列化&#xff1f; 2、Django REST Framework中的序列化和反序列化 3、安装与配置&#xff08;第10章是从零开始&#xff09; 3.1 安装 3.2 配置 4、基本使用 4.1 创建序列化器 4.2 使用序列化器&#xff08;将数据序列化返回给前端&#xff…...

【Golang】Golang的Map的线程安全问题

文章目录 前言一、场景介绍二、线程安全的Map的使用四、总结 前言 在 Golang 编程中&#xff0c;map 是一种常用的数据结构&#xff0c;用于存储键值对。然而&#xff0c;Golang 的 map 在并发访问时是线程不安全的。如果多个 goroutine 同时读写同一个 map&#xff0c;可能会…...

指向指针的指针+ 值传递的理解

//17、下面的程序会出现什么结果 #include #include void getmemory(char *p) { p(char *) malloc(100); strcpy(p,”hello world”); } int main( ) { char *strNULL; getmemory(str); printf(“%s/n”,str); free(str); return 0; } // 程序崩溃&#xff0c…...

CSS常用定位

一、relative 相对原先的位置进行定位 {position: relative;left: 50px; /* 相对原先位置左边的距离 */top: 100px; /* 相对原先位置上边的距离 */ } 二、absolute 绝对定位&#xff0c;是相对于最近有定位的父级元素进行定位 {position: absolute;righ…...

【Linux】从零开始使用多路转接IO --- select

碌碌无为&#xff0c;则余生太长&#xff1b; 欲有所为&#xff0c;则人生苦短。 --- 中岛敦 《山月记》--- 从零开始认识五种IO模型 1 前言2 认识多路转接select3 多路转接select等待连接4 完善代码5 总结 1 前言 上一篇文章我们讲解了五种IO模型的基本概念&#xff0c;并…...

ArcGIS Pro SDK (二十一)渲染

ArcGIS Pro SDK (二十一)渲染 文章目录 ArcGIS Pro SDK (二十一)渲染1 定义唯一值呈现器定义2 为最新观测值设置唯一值渲染器3 为先前的观测值设置唯一值渲染器4 设置简单的渲染器以绘制轨迹线5 检查先前的观测值和轨道线可见性6 使轨迹线和先前的观测点可见7 检索当前观测…...

FPGA在物联网边缘计算中的应用!!!

FPGA&#xff08;现场可编程门阵列&#xff09;在物联网边缘计算中的应用正变得越来越重要。边缘计算是一种分布式计算架构&#xff0c;它将数据的处理分散到网络的边缘&#xff0c;靠近数据源&#xff0c;而不是集中在数据中心处理。以下是FPGA在物联网边缘计算中的几个关键应…...

【解决】Linux环境中mysqlclient安装失败问题

问题描述 在Linux系统下安装myslclient报异常。系统为Centos 8 使用 pip install mysqlclient 报出下面的异常 error: subprocess-exited-with-error Getting requirements to build wheel did not run successfully.│ exit code: 1╰─> [30 lines of output]/bin/sh: pkg…...

✨ Midjourney中文版:创意启航,绘梦无界 ✨

Midjourney AI超强绘画 (原生态系统&#xff09;用户端&#xff1a;Ai Loadinghttps://www.mjdiscord.com 项目详细介绍飞书文档&#xff1a;Docshttps://ivqklkndl4k.feishu.cn/docx/GRnMdCbcooWkwTx1RU4cZjGVnzb?fromfrom_copylk &#x1f310; 无缝体验&#xff0c;中文定制…...

软件(1)

软件 常考软件 图像软件 Flash 一款二维动画处理软件 photoshop 图像处理界的“巨无霸” ACDSee ACDSee是常用的图片管理编辑软件&#xff0c;尽管也可以支持WAV格式的音频播放&#xff0c; 但目前主要是作为看图软件 音频软件 Winamp Winamp是数字媒体播放的先驱Audition Audi…...

linux perf 环境部署和基本测试(基于Ubuntu20.04)

1,linux 安装perf sudo apt-ge install linux-tools-common sudo apt-get install linux-tools-$(uname -r) linux-tools-generic -y 2 补充安装 sudo apt-get install python3-q-text-as-data 3&#xff0c;perf常用命令 larkubuntu:~$ perf usage: perf [--version] [--hel…...

【网络面试篇】HTTP(1)(笔记)——状态码、字段、GET、POST、缓存

目录 一、相关问题 1. HTTP请求常见的状态码和字段&#xff1f; &#xff08;1&#xff09;状态码 &#xff08;2&#xff09;字段 ① Host 字段 ② Content-length 字段 ③ Connection 字段 ④ Content-Type 字段 ⑤ Content-Encoding 字段 2. GET 和 POST 的区别&a…...

HTML 基础标签——分组标签 <div>、<span> 和基础语义容器

文章目录 1. `<div>` 标签特点用途示例2. `<span>` 标签特点用途示例3. `<fieldset>` 标签特点用途示例4. `<section>` 标签特点用途示例5. `<article>` 标签特点用途示例总结HTML中的分组(容器)标签用于结构化内容,将页面元素组织成逻辑区域…...

SS928V100 ISP常见问题列表

下载链接&#xff1a; https://download.csdn.net/download/quantum7/89948226 1 FAQ 1 1.1 ISP 1 1.1.1 如何解决整体锐度不足 1 1.1.2 如何解决图像发蒙问题&#xff0c;提高通透性 2 1.1.3 如何解决低照度清晰度差 2 1.1.4 如何解决图像清晰度与物体边缘白边和黑边问题…...

AI写诗:自动版大唐宫体诗

大唐学子&#xff0c;手拿一本小卷&#xff08;类书&#xff09;&#xff0c;从中挑选过去他们&#xff08;权威&#xff09;认为好的词来拼接一首诗&#xff0c;此类诗词称作“宫体诗”&#xff0c;在初唐时期甚是流行。 写“宫体诗”的过程有木有那么一丝丝的熟悉&#xff1f…...

Java复习31(PTA)

sdust-Java-字符串集合求并集 分数 15 全屏浏览 切换布局 作者 张峰 单位 山东科技大学 从键盘接收N个英文字符串&#xff08;其中不同的字符串数量大于10&#xff09;&#xff0c;从头开始取5个不同的字符串放入一个集合S1&#xff0c;然后接着取5个不同的字符串放入另一个…...

【Linux系列】Linux 系统中的软连接管理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

@layer(级联层)

在css样式表(文件)中声明layer为样式添加级联层,其意义在于可以使用它重新定义样式的叠层关系. layer后声明的级联层里面的样式将覆盖前声明的级联层里面的相同属性.在级联层外声明的样式会覆盖级联层里面的相同属性样式,同一层级里面的样式冲突,依然按照优先级来计算. 在级联层…...

nginx代理websocket服务

一、nginx代理websocket服务 一&#xff09;nginx代理ws服务 在nginx中&#xff0c;可以通过proxy_pass指令来代理WebSocket服务。 以下是一个示例配置&#xff1a; map $http_upgrade $connection_upgrade {default upgrade; close; }upstream ws_backend {server 127.0.0.1:…...

第二十七章 Vue异步更新之$nextTick

目录 一、概述 二、完整代码 2.1. main.js 2.2. App.vue 一、概述 需求&#xff1a;编辑标题, 弹出显示编辑框自动聚焦 1. 点击编辑&#xff0c;显示编辑框 2. 让编辑框&#xff0c;立刻获取焦点 我们常规的思路可能会编写如下代码来实现&#xff1a; 问题&#xff1a…...

【51 Pandas+Pyecharts | 深圳市共享单车数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 处理起始时间、结束时间2.4 增加骑行时长区间列2.5 增加骑行里程区间列 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 各…...

【Clikhouse 探秘】ClickHouse 物化视图:加速大数据分析的新利器

&#x1f449;博主介绍&#xff1a; 博主从事应用安全和大数据领域&#xff0c;有8年研发经验&#xff0c;5年面试官经验&#xff0c;Java技术专家&#xff0c;WEB架构师&#xff0c;阿里云专家博主&#xff0c;华为云云享专家&#xff0c;51CTO 专家博主 ⛪️ 个人社区&#x…...

线程相关题(线程池、线程使用、核心线程数的设置)

目录 线程安全的什么情况用&#xff1f;情况下用线程安全的类&#xff1f; 线程池线程方面的优化 线程池调优主要涉及以下几个关键参数。 线程不安全原因? 1. 共享资源访问冲突 2. 缺乏原子操作 3. 内存可见性问题 4. 重排序问题 如何解决线程不安全的问题&#xff1…...

2181、合并零之间的节点

2181、[中等] 合并零之间的节点 1、问题描述&#xff1a; 给你一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val 0 。 对于每两个相邻的 0 &#xff0c;请你将它们之间的所有节点合并成一个节点&#xff…...

powerlaw:用于分析幂律分布的Python库

引言 幂律分布在游戏行业中非常重要。在免费游戏模式下&#xff0c;玩家的付费行为往往遵循幂律分布。少数“鲸鱼玩家”贡献了大部分的收入&#xff0c;而大多数玩家可能只进行少量或不进行付费。通过理解和应用幂律分布&#xff0c;游戏开发者可以更好地分析和预测玩家行为&a…...