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;
}

如下圖:
在這裏插入圖片描述

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