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