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;
}
如下圖: