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->pxPrevious; //(2)
	
	//如果要刪除的列表項爲END,那麼pxIndex的指向向前移動一項;
	if(pxList->pxIndex == pxItemToRemove)
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		//mtCOVERAGE_TEST_MARKER();
	}
	
	pxItemToRemove->pvContainer = NULL; //(3)
	(pxList->uxNumberOfItems)--;
	
	return pxList->uxNumberOfItems;
	
}

擦除函數相對比較簡單,這裏就不畫圖了;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章