当前位置: 首页 > 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…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...