FreeRTOS連結串列實現

楊登輝dh發表於2020-10-19

直接上原始碼分析

void vListInitialise( List_t * const pxList )
{

   pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );           /* 此時連結串列中只有一個列表項(結點) */

   pxList->xListEnd.xItemValue = portMAX_DELAY;            /* 輔助值,用來做升序 */

  pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );     

  pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd )

  pxList->uxNumberOfItems = ( UBaseType_t ) 0U;              /* 記錄列表中節點的數量 */

}

 

void vListInitialiseItem( ListItem_t * const pxItem )
{

   /* 標記此節點屬於哪個列表。初始化為NULL */

  pxItem->pxContainer = NULL;

}

void vListInsertEnd( List_t * const pxList,
                         ListItem_t * const pxNewListItem )

{

  ListItem_t * const pxIndex = pxList->pxIndex;      /* 先拿到這個連結串列的索引,網上說這個索引指向列表項的頭部,但是初始化並沒有這個操作 */

 

  pxNewListItem->pxNext = pxIndex;            /* 新插入的節點的下一個節點就是這個pxIndex節點 ,新插入的節點指向了末尾節點 */
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;  /* pxIndex->pxPrevious 指向的是列表的末尾節點,pxNewListItem->pxPrevious 新插入的節點的上一個等於末尾的節點,不知道為什麼要這樣 */

 

  pxIndex->pxPrevious->pxNext = pxNewListItem;    /* pxIndex->pxPrevious->pxNext本來是指向自己,現在指向的是新節點,等於連線起來 */

  pxIndex->pxPrevious = pxNewListItem;        /* 基本操作了,連結節點 */

 

  pxNewListItem->pxContainer = pxList;    /* 標記狀態 */

  ( pxList->uxNumberOfItems )++;    /* 節點加1,這裡為什麼加括號? */

}

 

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;      /* 如果要插入的節點的值等於最大值,那就插在End的前一個節點的位置 */
    }

  

else

{

  /*  首先pxIterator指向此連結串列的最後一個節點,判斷新插入的節點的值和pxIterator下一個節點的值

      此時 pxIterator->pxNext->xItemValue就是首節點的值,(為什麼是首節點,因為初始化pxIterator指向了End節點,pxIterator = ( ListItem_t * ) &( pxList->xListEnd ))

    如果插入的值大於pxIterator->pxNext->xItemValue(第一次是首節點的值),那麼pxIterator=pxIterator->pxNext ,即指向下一個節點繼續迴圈

    如果插入的值小於pxIterator->pxNext->xItemValue,那麼就說明找到了要插入的地方

    那就是新插入的到pxIterator的後面,要插入的節點就是pxIterato和 pxIterato->next之間。

    */

  for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) {  }

}

   pxNewListItem->pxNext = pxIterator->pxNext;  /* 首先把 pxIterator->pxNext 賦值給 pxNewListItem->pxNext,讓新列表項指向原本列表中下一個列表項 */

   pxNewListItem->pxNext->pxPrevious = pxNewListItem;  /*  把 pxNewListItem->pxNext(也就是原本列表中下一個列表項)的 pxNewListItem->pxNext->pxPrevious 成員指向待插入列表項 pxNewListItem,實現雙向連結串列 */

      pxNewListItem->pxPrevious = pxIterator;    /* 新插入的上一個指向pxIterator,就是上面說的,新的節點插到pxIterator的後面 */

      pxIterator->pxNext = pxNewListItem;      /* pxIterator->pxNext : 原來的pxIterator節點  (此時只是插入節點,xIterator->pxNext一定要指向pxNewListItem,實現節點的連結)的下一個就是新的節點了 */

   pxNewListItem->pxContainer = pxList;    /* 老套路了 */  

          ( pxList->uxNumberOfItems )++; /* 列表項個數加1 */

}

 

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

{

  List_t * const pxList = pxItemToRemove->pxContainer;    /* 得到要刪除節點連結串列 */

  pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;  /* 這裡就只是改變指標前後連結 */

  pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

  mtCOVERAGE_TEST_DELAY();    /* 這裡為什麼要存在空函式? */

  if( pxList->pxIndex == pxItemToRemove )    /* 很好理解,不做解釋 */
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }

  pxItemToRemove->pxContainer = NULL;    /* 已經都刪除節點了,這個節點的屬主連結串列肯定不存在啊 */
     ( pxList->uxNumberOfItems )--;      /* 老套路了 */

 

  return pxList->uxNumberOfItems;    /* 返回這個連結串列還有幾個節點 */

}

 

// 仍有疑問,希望有人看到能解答一下,在下感激不盡。

 

相關文章