双向链表的理解

背景

代码中经常会出现双向链表,对于双向链表的插入和删除有对应的API函数接口,但直观的图表更容易理解,所以本文会对rt-thread内核代码中提供的双向链表的一些API函数操作进行绘图,方便后续随时查看。

代码块

rt-thread中提供的代码段包括:
链表定义rtdef.h

/*** Double List structure*/
struct rt_list_node
{struct rt_list_node *next;                          /**< point to next node. */struct rt_list_node *prev;                          /**< point to prev node. */
};
typedef struct rt_list_node rt_list_t;                  /**< Type for lists. */

API操作定义rtserver.h

/*** @addtogroup KernelService*//**@{*//*** rt_container_of - return the start address of struct type, while ptr is the* member of struct type.*/
#define rt_container_of(ptr, type, member) \((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))/*** @brief initialize a list object*/
#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) }/*** @brief initialize a list** @param l list to be initialized*/
rt_inline void rt_list_init(rt_list_t *l)
{l->next = l->prev = l;
}/*** @brief insert a node after a list** @param l list to insert it* @param n new node to be inserted*/
rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{l->next->prev = n;n->next = l->next;l->next = n;n->prev = l;
}/*** @brief insert a node before a list** @param n new node to be inserted* @param l list to insert it*/
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
{l->prev->next = n;n->prev = l->prev;l->prev = n;n->next = l;
}/*** @brief remove node from list.* @param n the node to remove from the list.*/
rt_inline void rt_list_remove(rt_list_t *n)
{n->next->prev = n->prev;n->prev->next = n->next;n->next = n->prev = n;
}/*** @brief tests whether a list is empty* @param l the list to test.*/
rt_inline int rt_list_isempty(const rt_list_t *l)
{return l->next == l;
}/*** @brief get the list length* @param l the list to get.*/
rt_inline unsigned int rt_list_len(const rt_list_t *l)
{unsigned int len = 0;const rt_list_t *p = l;while (p->next != l){p = p->next;len ++;}return len;
}/*** @brief get the struct for this entry* @param node the entry point* @param type the type of structure* @param member the name of list in structure*/
#define rt_list_entry(node, type, member) \rt_container_of(node, type, member)/*** rt_list_for_each - iterate over a list* @pos:    the rt_list_t * to use as a loop cursor.* @head:   the head for your list.*/
#define rt_list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)/*** rt_list_for_each_safe - iterate over a list safe against removal of list entry* @pos:    the rt_list_t * to use as a loop cursor.* @n:      another rt_list_t * to use as temporary storage* @head:   the head for your list.*/
#define rt_list_for_each_safe(pos, n, head) \for (pos = (head)->next, n = pos->next; pos != (head); \pos = n, n = pos->next)/*** rt_list_for_each_entry  -   iterate over list of given type* @pos:    the type * to use as a loop cursor.* @head:   the head for your list.* @member: the name of the list_struct within the struct.*/
#define rt_list_for_each_entry(pos, head, member) \for (pos = rt_list_entry((head)->next, typeof(*pos), member); \&pos->member != (head); \pos = rt_list_entry(pos->member.next, typeof(*pos), member))/*** rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry* @pos:    the type * to use as a loop cursor.* @n:      another type * to use as temporary storage* @head:   the head for your list.* @member: the name of the list_struct within the struct.*/
#define rt_list_for_each_entry_safe(pos, n, head, member) \for (pos = rt_list_entry((head)->next, typeof(*pos), member), \n = rt_list_entry(pos->member.next, typeof(*pos), member); \&pos->member != (head); \pos = n, n = rt_list_entry(n->member.next, typeof(*n), member))/*** rt_list_first_entry - get the first element from a list* @ptr:    the list head to take the element from.* @type:   the type of the struct this is embedded in.* @member: the name of the list_struct within the struct.** Note, that list is expected to be not empty.*/
#define rt_list_first_entry(ptr, type, member) \rt_list_entry((ptr)->next, type, member)

重点函数

rt_list_init()
rt_list_insert_after()
rt_list_insert_before()
rt_list_remove()

重点函数理解

rt_list_init(rt_list_t *l)

rt_inline void rt_list_init(rt_list_t *l)
{l->next = l->prev = l;
}

初始化当前链表l,即当前链表l的pre和next都是指向自己。
在这里插入图片描述

rt_list_insert_after(rt_list_t *l, rt_list_t *n)

rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n)
{l->next->prev = n;n->next = l->next;l->next = n;n->prev = l;
}

将新链表n1插入到l之后
在这里插入图片描述
将新链表n2插入到l之后
在这里插入图片描述
将新链表n3插入到l之后
在这里插入图片描述

rt_list_insert_before(rt_list_t *l, rt_list_t *n)

rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n)
{l->prev->next = n;n->prev = l->prev;l->prev = n;n->next = l;
}

将新链表n1插入到l之前
在这里插入图片描述
将新链表n2插入到l之前
在这里插入图片描述

rt_list_remove(rt_list_t *n)

rt_inline void rt_list_remove(rt_list_t *n)
{n->next->prev = n->prev;n->prev->next = n->next;n->next = n->prev = n;
}

从已有链表中移除当前链表,如原链表
在这里插入图片描述
从此链表中移除n2,则
在这里插入图片描述

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

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

相关文章

大文件上传源码,支持单个大文件与多个大文件

大文件上传源码&#xff0c;支持单个大文件与多个大文件 Ⅰ 思路Ⅱ 具体代码前端--单个大文件前端--多个大文件前端接口后端 Ⅰ 思路 具体思路请参考我之前的文章&#xff0c;这里分享的是上传流程与源码 https://blog.csdn.net/sugerfle/article/details/130829022 Ⅱ 具体代码…

Unity中的静态合批使用整理

静态批处理是一种绘制调用批处理方法&#xff0c;它组合不移动的网格以减少绘制调用。它将组合的网格转换为世界空间&#xff0c;并为它们构建一个共享顶点和索引缓冲区。然后&#xff0c;对于可见网格&#xff0c;Unity 会执行一系列简单的绘制调用&#xff0c;每个调用之间几…

【机器学习中的基本术语:特征、样本、训练集、测试集、监督/无监督学习】

机器学习基本术语详解 1. 特征&#xff08;Feature&#xff09; 定义&#xff1a;数据的属性或变量&#xff0c;用于描述样本的某个方面。作用&#xff1a;模型通过学习特征与目标之间的关系进行预测。示例&#xff1a; 预测房价时&#xff0c;特征可以是 面积、地段、房龄。…

C++学习之路:指针基础

目录 指针介绍与基本用法双重指针函数指针空指针与野指针函数参数的指针传递最后 指针一般在C/C语言学习的后期接触&#xff0c;这样就导致指针给新手一种高深莫测、难以掌握的刻板印象。但实际上指针的使用很简单&#xff0c;并且还能够极大的提高程序的灵活性&#xff0c;帮助…

【服务日志链路追踪】

MDCInheritableThreadLocal和spring cloud sleuth 在微服务架构中&#xff0c;日志链路追踪&#xff08;Logback Distributed Tracing&#xff09; 是一个关键需求&#xff0c;主要用于跟踪请求在不同服务间的调用链路&#xff0c;便于排查问题。常见的实现方案有两种&#x…

Kafka+Zookeeper从docker部署到spring boot使用完整教程

文章目录 一、Kafka1.Kafka核心介绍&#xff1a;​核心架构​核心特性​典型应用 2.Kafka对 ZooKeeper 的依赖&#xff1a;3.去 ZooKeeper 的演进之路&#xff1a;注&#xff1a;&#xff08;本文采用ZooKeeper3.8 Kafka2.8.1&#xff09; 二、Zookeeper1.核心架构与特性2.典型…

JUC系列JMM学习之随笔

JUC: JUC 是 Java 并发编程的核心工具包,全称为 Java Util Concurrent,是 java.util.concurrent 包及其子包的简称。它提供了一套强大且高效的并发编程工具,用于简化多线程开发并提高性能。 CPU核心数和线程数的关系:1核处理1线程(同一时间单次) CPU内核结构: 工作内…

The Rust Programming Language 学习 (九)

泛型 每一个编程语言都有高效处理重复概念的工具。在 Rust 中其工具之一就是 泛型&#xff08;generics&#xff09;。泛型是具体类型或其他属性的抽象替代。我们可以表达泛型的属性&#xff0c;比如他们的行为或如何与其他泛型相关联&#xff0c;而不需要在编写和编译代码时知…

蓝桥杯 混乘数字

问题描述 混乘数字的定义如下&#xff1a; 对于一个正整数 n&#xff0c;如果存在正整数 a 和 b&#xff0c;使得&#xff1a; n a b且 a 与 b 的十进制数位中每个数字出现的次数之和&#xff0c;与 n 中对应数字出现的次数相同&#xff0c;则称 n 为混乘数字。 示例 对于…

CExercise04_1位运算符_2 定义一个函数判断给定的正整数是否为2的幂

题目&#xff1a; 给定一个正整数&#xff0c;请定义一个函数判断它是否为2的幂(1, 2, 4, 8, 16, …) 分析&#xff1a; &#xff1a; 代码 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdbool.h>/* 给定一个正整数&#xff0c;请定义一个函数…

SSL证书不可信的原因有哪些?(国科云)

SSL证书用于在客户端和服务器端之间建立一条加密通道&#xff0c;确保数据在传输过程中的安全性和完整性。然而&#xff0c;在实际应用中&#xff0c;我们有时会遇到SSL证书不可信的情况&#xff0c;严重影响了用户对网站的信任度。那么&#xff0c;SSL证书不可信的原因究竟有哪…

[王阳明代数讲义]琴语言类型系统工程特性

琴语言类型系统工程特性 层展物理学组织实务与艺术与琴生生.物机.械科.技工.业研究.所软凝聚态物理开发工具包社会科学气质砥砺学人生意气场社群成员魅力场与心气微积分社会关系力学 意气实体过程图论信息编码&#xff0c;如来码导引 注意力机制道装Transformer架构的发展标度律…

自抗扰ADRC之二阶线性扩展状态观测器(LESO)推导

1.龙伯格观测器 实际工程应用中&#xff0c;状态变量有时难以使用传感器直接测量&#xff0c;在这种情况下&#xff0c;使用状态观测器估计系统实际状态是非常常见的做法。最出名的状态观测器当属龙伯格博士在1971年发表于TAC的An Introduction to Observer[1]一文中提出的基于…

从头开发一个Flutter插件(二)高德地图定位插件

开发基于高德定位SDK的Flutter插件 在上一篇文章里具体介绍了Flutter插件的具体开发流程&#xff0c;从创建项目到发布。接下来将为Flutter天气项目开发一个基于高德定位SDK的Flutter定位插件。 申请key 首先进入高德地图定位SDK文档内下载定位SDK&#xff0c;并按要求申请A…

分布式锁之redis6

一、分布式锁介绍 之前我们都是使用本地锁&#xff08;synchronize、lock等&#xff09;来避免共享资源并发操作导致数据问题&#xff0c;这种是锁在当前进程内。 那么在集群部署下&#xff0c;对于多个节点&#xff0c;我们要使用分布式锁来避免共享资源并发操作导致数据问题…

ubuntu中使用安卓模拟器

本文这里介绍 使用 android studio Emulator &#xff0c; 当然也有 Anbox (Lightweight)&#xff0c; Waydroid (Best for Full Android Experience), 首先确保自己安装了 android studio &#xff1b; sudo apt update sudo apt install openjdk-11-jdk sudo snap install…

二语习得理论(Second Language Acquisition, SLA)如何学习英语

二语习得理论&#xff08;Second Language Acquisition, SLA&#xff09;是研究学习者如何在成人或青少年阶段学习第二语言&#xff08;L2&#xff09;的理论框架。该理论主要关注语言习得过程中的认知、社会和文化因素&#xff0c;解释了学习者如何从初学者逐渐变得流利并能够…

WinDbg. From A to Z! 笔记(下)

原文链接: WinDbg. From A to Z! 文章目录 使用WinDbg临界区相关命令示例 -- 查看临界区其他有用的命令 WinDbg中的伪寄存器自动伪寄存器 WinDbg中的表达式其他操作默认的表达式计算方式 WinDbg中的重命名调试器命令语言编程控制流命令程序执行 WinDbg 远程调试事件监控WinDbg …

RainbowDash 的旅行

D RainbowDash 的旅行 - 第七届校赛正式赛 —— 补题 题目大意&#xff1a; 湖中心有一座岛&#xff0c;湖的外围有 m m m 间木屋&#xff08;围绕小岛&#xff09; &#xff0c;第 i i i 间木屋和小岛之间有 a i a_i ai​ 座 A A A 类桥&#xff0c; b i b_i bi​ 座 B …

MySQL-SQL-DDL语句、表结构创建语句

一.SQL SQL&#xff1a;一门操作关系型数据库的编程语言&#xff0c;定义操作所有关系型数据库的统一标准 二. DDL-数据库 1. 查询所有数据库 命令&#xff1a;show databases; 2. 查询当前数据库 命令&#xff1a;select database(); 3. 创建数据库 命令&#xff1a;create da…