FreeRTOS List的结尾插入,中间插入,删除操作过程分析(3)

前言
  1. 本博文基于FreeRTOSV9.0.0和COTEX-M3内核的文件(我在网上看的不同的版本在功能和效果上有一定差异);
  2. 本博文针对列表和列表项相关操作的图文分析,大多是根据自己的理解去分析的;
  3. 如有错误之处还请多多指教;
List 和List Item结构体定义
//节点(列表项)结构体
struct xLIST_ITEM			
{
	TickType_t xItemValue;   				//节点编号,用于帮助节点做升序排列;
	struct xLIST_ITEM * pxNext;			//指向链表下一个节点;
	struct xLIST_ITEM * pxPrevious; //指向链表前一个节点;
	void * pvOwner;									//指向拥有该节点的内核对象,通常为TCB 任务控制块 (task control block);
	void * pvContainer;							//指向该节点所在的列表;
};

typedef struct xLIST_ITEM ListItem_t;  //节点数据结构类型重定义;

/*
	mini链表节点结构体定义作为双链表的结尾
	因为双向链表是首尾相连,头即是尾,尾既是头;
*/

struct xMINI_LIST_ITEM
{
  TickType_t xItemvalue;							//节点编号,用于帮助节点做升序排列
	struct xLIST_ITEM * pxNext;					//指向链表下一个节点;
	struct xLIST_ITEM *	pxPrevious;			//指向链表前一个节点;
	
};
typedef struct xMINI_LIST_ITEM  MiniListItem_t; 


//链表(列表)根节点结构体
struct xLIST
{
	UBaseType_t uxNumberOfItems;       	//链表节点数(列表项);
	ListItem_t * pxIndex;								//链表节点索引指针;
	MiniListItem_t xListEnd;						//包含最大可能项值的列表项,这意味着它总是在列表的末尾,因此用作标记。

};
typedef struct xLIST List_t;					//链表结构体类型重定义;

我个人对List结构体的理解
struct xLIST
{
	UBaseType_t uxNumberOfItems;       	
	ListItem_t * pxIndex;								
	MiniListItem_t xListEnd;						

};
typedef struct xLIST List_t;					//链表结构体类型重定义;

每个被定义了的列表都有一个List结构体变量,这是整个列表最重要的部分,可以称为生产者;具有以下特性:

  1. 作为一个不计入列表项总数(uxNumberOfItems)的列表项存在于列表的尾端(首端),承前启后,前为辅助值(列表项编号)最大的列表项,后为列表首项,从而使得列表为双向环形 (如图一);
  2. 列表结构体变量中的pxIndex成员,始终指向自身结构体的xListEnd地址;所以作为(ListItem_t *)类型变量,多所指示的前一项和后一项始终保持同步 (如图二);
    在这里插入图片描述
结尾插入函数:vListInsert()过程分析
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t * const pxIndex = pxList->pxIndex;

	pxNewListItem->pxNext = pxIndex;									//(1)
	pxNewListItem->pxPrevious = pxIndex->pxPrevious;		//(2)

	pxIndex->pxPrevious->pxNext = pxNewListItem;				//(3)
	pxIndex->pxPrevious = pxNewListItem;								//(4)

	pxNewListItem->pvContainer = ( void * ) pxList;					

	( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/

其他几个步骤都很好理解,主要是代码中标注的(1)~(4),尾端插入过程如下:
在这里插入图片描述

中间插入函数:vListInsert()

其实并没有强调是“中间”,有可能还是结尾;

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;  		//(1)		
	}
	else
	{
		for(pxIterator = (ListItem_t *)&(pxList->xListEnd);   //(A)
				pxIterator->pxNext->xItemValue <= xValueOfInsertion; //(B)
				pxIterator = pxIterator->pxNext)			//(C)
		{
		    //这里并不实现什么功能,所有的操作在上面括号中就完成了;
		}
	}
	
	pxNewListItem->pxNext = pxIterator->pxNext;  //(2)
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;//(3)
	pxNewListItem->pxPrevious = pxIterator;		//(4)
	pxIterator->pxNext = pxNewListItem;				//(5)
	
	pxNewListItem->pvContainer = (void *)pxList;
	(pxList->uxNumberOfItems)++;

}

分了两种情况:
①:xValueOfInsertion == portMAX_DELAY 过程从(1)~(5)
在这里插入图片描述
②:这个情况相对好理解一些,插入的流程为:根据要插入的列表项的xItemValue值的大小按照升序的原则,在列表中从第一个(node1)列表项开始,寻找列表项中列表项的xItemValue值刚好大于New列表项的xItemValue值的哪一个列表项,将New列表项插入到它前面;

在这里插入图片描述

删除函数:uxListRemove()
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{
	List_t * const pxList = (List_t *)pxItemToRemove->pvContainer;
	
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;  //(1)
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; //(2)
	
	//如果要删除的列表项为END,那么pxIndex的指向向前移动一项;
	if(pxList->pxIndex == pxItemToRemove)
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		//mtCOVERAGE_TEST_MARKER();
	}
	
	pxItemToRemove->pvContainer = NULL; //(3)
	(pxList->uxNumberOfItems)--;
	
	return pxList->uxNumberOfItems;
	
}

擦除函数相对比较简单,这里就不画图了;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值