- C语言链表简介
- 列表及列表项
- 链表相关 *** 作
列表及列表项链表好比一个圆形的晾衣架,上面有很多的钩子,钩子首尾相连。
链表由许多节点组成,节点与节点之 间首尾相连。
晾衣架的钩子本身不能代表很多东西,但是钩子本身可以挂很多东西。
同样链表也类似,链表的节点本身不能存储太多东西,但是节点跟晾衣架的钩子一样,可以挂很多数据。
- 列表项
/* 列表节点数据结构定义[list.h] */
typedef struct xLIST_ITEM {
TickType_t xItemValue; /* 节点排序,一般用于记录任务从挂起状态返回就绪态的绝对时间 */
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
void *pvOwner; /* 指向拥有此节点的对象,通常是TCB */
struct xLIST *pxContainer; /* 指向此节点所在的列表(链表) */
}
- 列表
/* 列表数据结构定义[list.h] */
typedef struct xLIST {
UBaseType_t uxNumberOfItems; /* 链表中包含的节点数目,不包含根节点 */
ListItem_t *pxIndex; /* 用于链表中对节点的索引 */
MiniListItem xListEnd; /* 根节点,属于列表最初的钩子 */
} List_t;
typedef struct xMINI_LIST_ITEM {
TickType_t xItemValue; /* 默认值为FreeRtos中的最大值,代表此节点是所有节点中的最后一个 */
ListItem_t *pxNext;
ListItem_t *pxPrevious;
} MiniListItem_t;
链表相关 *** 作列表中默认包含的节点 xListEnd 仅用于抓取最开始加入的节点,也被称为根节点。
一般认为 xListEnd->pxNext 指向列表加入的第一个节点,而 xListEnd->pxPrevious 指向
列表加入的最后一个节点。
- 列表项初始化
void vListInitializeItem(ListItem_t * const pxItem)
{
/* 初始化该节点所在链表为空,表示节点还没有插入任何链表 */
pxItem->pvContainer = NULL;
}
- 列表初始化
void vListInitialise(List_t * const pxList)
{
/* 列表索引指针默认指向根节点 */
pxList->pxIndex = (ListItem_t *)&(pxList->xListEnd);
/* 设置根节点的辅助排序值最大,确保是链表的最后节点*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = (ListItem_t *)&(pxList->xListEnd);
pxList->xListEnd.pxPrevious = (ListItem_t *)&(pxList->xListEnd);
/* 链表节点计数器初始为0,计数不包括根节点 */
pxList->uxNumberOfItems = (UBaseType_t)0U;
}
- 将节点插入链表尾部
/* 根据代码可知,其实是将新节点插入到列表索引指针pxIndex指向节点的前面,
而不是根节点前面,而pxIndex只是初始化时指向了根节点 */
void vListInsertEnd(List_t * const pxList, ListItem_t * const pxNewListItem)
{
ListItem_t * const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
pxNewListItem->pxContainer = pxList;
(pxList->uxNumberOfItems)++;
}
- 将节点按照升序排列插入到链表
void vListInsert(List_t * const pxList, ListItem_t * const pxNewListItem)
{
ListItem_t * pxIterator;
/* 获取节点的辅助排序值 */
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
/* 寻找节点要插入的位置 */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for(pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
pxIterator->pxNext->xItemValue <= xValueOfInsertion;
pxIterator = pxIterator->pxNext)
{
/* do nothing */
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext->pxPrevious = pxNewListItem;
pxIterator->pxNext = pxNewListItem;
/* 记住节点所在列表 */
pxNewListItem->pxContainer = pxList;
/* 列表计数器++ */
(pxList->uxNumberOfItems)++;
}
- 将节点从列表删除
/* 个人疑问:pxItemToRemove在被删除后,它的pxNext和pxPrevious仍然指向原来的前后节点,
那如果在相邻节点(0,1,2)中,删除1节点,再删除2节点后,此时如果不小心再次删除1节点,
岂不是0,2节点会再次相连? */
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{
/* 获取节点所在列表 */
List_t * const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* 避免列表索引指针pxIndex指向已被删除的节点 */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pxContainer = NULL;
(pxList->uxNumberOfItems)--;
return pxList->uxNumberOfItems;
}
- 带参宏函数
/* 初始化节点的拥有者 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) \
( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* 获取节点的拥有者 */
#define listGET_LIST_ITEM_OWNER( pxListItem ) \
( ( pxListItem )->pvOwner )
/* 初始化节点排序辅助值 */
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) \
( ( pxListItem )->xItemValue = ( xValue ) )
/* 获取节点排序辅助值 */
#define listGET_LIST_ITEM_VALUE( pxListItem ) \
( ( pxListItem )->xItemValue )
/* 获取列表根节点的排序辅助值 */
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) \
( ( ( pxList )->xListEnd ).pxNext->xItemValue )
/* 获取列表的第一个节点 */
#define listGET_HEAD_ENTRY( pxList ) \
( ( ( pxList )->xListEnd ).pxNext )
/* 获取节点的下一个节点 */
#define listGET_NEXT( pxListItem ) \
( ( pxListItem )->pxNext )
/* 获取列表的根节点 */
#define listGET_END_MARKER( pxList ) \
( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
/* 判断列表是否为空 */
#define listLIST_IS_EMPTY( pxList ) \
( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )
/* 获取列表的节点数 */
#define listCURRENT_LIST_LENGTH( pxList ) \
( ( pxList )->uxNumberOfItems )
/* 返回当前节点的下一个节点的owner,同一优先级的任务的按照时间片的方式切换就与此函数有关 */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
{
List_t * const pxConstList = ( pxList );
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
/* 依次返回列表中所有的节点owner,但需要跳过根节点 */
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )
{
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;
}
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)