FreeRTOS
作者:解琛
时间:2020 年 8 月 18 日
一、链表
链表就好比一个圆形的晾衣架,晾衣架上面有很多钩子,钩子首尾相连。链表也是,链表由节点组成,节点与节点之间首尾相连。晾衣架的钩子本身不能代表很多东西,但是钩子本身却可以挂很多东西。
同样,链表也类似,链表的节点本身不能存储太多东西,或者说链表的节点本来就不是用来存储大量数据的,但是节点跟晾衣架的钩子一样,可以挂很多数据。
1.1 单向链表
单向链表中共有 n 个节点,前一个节点都有一个箭头指向后一个节点,首尾相连,组成一个圈。
节点本身必须包含一个节点指针,用于指向后一个节点。要通过链表存储的数据内嵌一个节点即可,这些要存储的数据通过这个内嵌的节点即可挂接到链表中,就好像晾衣架的钩子一样,把衣服挂接到晾衣架中。
链表作用是通过节点把离散的数据链接在一起,组成一个表。
链表常规的操作就是节点的插入和删除。
为了顺利的插入,通常一条链表会人为地规定一个根节点,这个根节点称为生产者。
通常根节点还会有一个节点计数器,用于统计整条链表的节点个数。
1.2 双向链表
双向链表与单向链表的区别就是节点中有两个节点指针,分别指向前后两个节点。
1.3 FreeRTOS 链表实现
1.3.1 实现链表节点
1.3.1.1 定义链表结构结构
struct xLIST_ITEM
{
TickType_t xItemValue; /* 辅助值,用于帮助节点做顺序排列; */
struct xLIST_ITEM * pxNext; /* 指向链表下一个节点; */
struct xLIST_ITEM * pxPrevious; /* 指向链表前一个节点; */
void * pvOwner; /* 用于指向该节点的拥有者,即该节点内嵌在哪个数据结构中,
属于哪个数据结构的一个成员;*/
void * pvContainer; /* 用于指向该节点所在的链表,通常指向链表的根节点;*/
};
typedef struct xLIST_ITEM ListItem_t; /* 节点数据类型重定义; */
1.3.1.2 链表节点初始化
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* 初始化该节点所在的链表为空,表示节点还没有插入任何链表 */
pxItem->pvContainer = NULL;
}
链表节点 ListItem_t 总共有 5 个成员,但是初始化的时候只需将 pvContainer 初始化为空即可,即清除其指向的链表,表示该节点还没有插入到任何链表。
1.3.2 实现链表根节点
1.3.2.1 定义链表根节点的数据结构
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; /* 链表节点计数器,用于表示该链表下有多少个节点,根节点除外; */
ListItem_t * pxIndex; /* 链表节点索引指针,用于遍历节点; */
MiniListItem_t xListEnd; /* 链表最后一个节点,实际也就是链表的第一个节点,即生产者; */
} List_t;
struct xMINI_LIST_ITEM
{
TickType_t xItemValue; /* 辅助值,用于帮助节点做升序排列; */
struct xLIST_ITEM * pxNext; /* 指向链表下一个节点; */
struct xLIST_ITEM * pxPrevious; /* 指向链表前一个节点; */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t; /* 精简节点数据类型重定义; */