FreeRTOS 链表的深度讲解

list.h里定义

/*节点结构体定义*/
struct xLIST_ITEM
{
	TickType_t xItemValue;  //辅助值,用于帮助节点做顺序排列          
	struct xLIST_ITEM *  pxNext;      
	struct xLIST_ITEM *  pxPrevious;  
	void * pvOwner;					  
	void *  pvContainer;		     
};
typedef struct xLIST_ITEM ListItem_t; 

/*迷你节点结构体定义,作为双链表的结尾*/
struct xMINI_LIST_ITEM
{
	TickType_t xItemValue;  //辅助值,用于节点升序                   
	struct xLIST_ITEM *  pxNext;  //指向链表下一节点            
	struct xLIST_ITEM *  pxPrevious;  //指向链表前一节点           
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;  

/*链表*/
typedef struct xLIST
{
	UBaseType_t uxNumberOfItems; //链表节点计数器   
	ListItem_t *  pxIndex;	//链表节点索引指针		
	MiniListItem_t xListEnd;	//链表最后一个节点
} List_t;

1、双链表插入尾部
原理:
在这里插入图片描述
入上图,就是将链表断开,然后重连的过程。
结合代码如下:

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->pvContainer = ( void * ) pxList;/* 链表节点计数器++ */ 
  ( pxList->uxNumberOfItems )++;} 

2、按照节点升序排列到链表
代码如下:

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 )
		{
			/* 不做任何事,只为寻找到节点位置。			
			*/			
		}
	}
//pxIterator 为插入的前一个
	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxPrevious = pxIterator;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxIterator->pxNext = pxNewListItem;

	/* 纪录节点所在的列表*/
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* 链表节点计数器++ */
	( pxList->uxNumberOfItems )++;
}

解释:为什么用一个for循环就找到了节点位置呢??看一个图片就一目了然了
在这里插入图片描述
大家可以看上图,特别注意,xLIST链表中MiniListItem_t;原子里面解释,这是最后的一个节点。大家注意了,这个节点的next是指向第一个节点pxprevous指向,最后一个节点。利用for 循环,从第一个开始遍历,直到遇到一个节点值比插入值大,然后跳出,此时就获取到了需要插入的节点位置pxIterator 。pxIterator 为插入的前一个。
寻找到位置后,接下来就是插入节点,与上面双链表插入尾部一模一样。断开,重连的一个过程。

如果上面的理解了,其他的我们一笔带过吧,都非常的简单了
3.链表的删除

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
	/*获取节点所在链表*/
	List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
   /*步骤1*/
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	/*步骤2*/
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* Make sure the index is left pointing to a valid item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}

	/* 初始化所在的链表为空,表示节点没有插入到链表 */
	pxItemToRemove->pvContainer = NULL;
	
	/* 链表节点计数值-- */
	( pxList->uxNumberOfItems )--;

	/*返回链表节点数 */
	return pxList->uxNumberOfItems;
}

如下图:
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值