目录
上篇文章介绍了 FreeRTOS 关于链表的基本概念,本篇将介绍如何插入和删除节点。
插入节点
节点插入链表,首先需要在要插入位置断开两个节点的连接,然后将插入节点和这两个节点分别连接。前后效果如下图。
以下为节点插入过程演示。
让新节点的next指向根节点;
让新节点的previous指向根节点的上一个节点;
让根节点的上一个节点的next指向新节点;
让根节点的previous指向新节点;
节点插入到尾部
此方法可以将节点插入到一个空的链表中,也就是将节点和根节点连接在一起,这个过程分为以下几个步骤:
1. 让根节点的下一个节点指向新节点。
2. 让根节点的上一个节点指向新节点。
3. 调整其他参数,使其根据实际情况进行调整。
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 )++;
}
上述代码所做的操作如下:
1. 将根节点的索引指针指向根节点的最后一个节点(即精简节点)。
2. 新节点的 pxNext 指向索引指针,即指向根节点。
3. 新节点的 pxPrevious 指向根节点。
4. 根节点的 pxNext 指向新节点。
5. 根节点的 pxPrevious 指向新节点。
6. 新节点的 pvContainer 指向根节点。
7. 根节点的节点计数器加1。
节点升序排列插入
这种插入方法依赖于 xItemValue ,也就是每个节点的序号。因此,我们在执行完新节点的初始化之后,需要为新节点的 xItemValue 赋值。
从根节点的下一个节点开始,xItemValue 的值越来越大,呈升序排列。根据这个序号的值找到应该插入的位置后,就会插入到链表中;如果链表存在和新节点序号一样的节点,则新节点会插入到这个节点的后面。
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 )
{
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pvContainer = ( void * ) pxList;
( pxList->uxNumberOfItems )++;
}
首先,获取新节点的序号,如果序号值等于节点数量的最大值,那么这个节点就会插入到根节点的前面;反之,则通过for循环来寻找要插入的位置。
当找到要插入位置之后,将节点插入,然后更新插入节点的 pvContainer 和根节点的节点计数器。
删除节点
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}
整个函数流程如下:
1. 首先获取要删除节点所在的链表;
2. 使要删除节点的下一个节点的previous指向要删除节点的上一个节点;
3. 使要删除节点的上一个节点的next指向要删除节点的下一个节点;
4. 调整将该链表的节点索引指针;
5. 初始化要删除节点所在的链表为空,表示节点还没有插入任何链表;
6. 然后将节点计数器减一并返回。
删除节点的整个过程大致和插入节点相反,一个是指向插入节点,一个是指向该节点的上一个节点。
到这一步为止,链表内容暂时告一段落。下一部分为任务的相关内容。