【数据结构】链表-双向非通用链表-源码


前言

  • 20201010
  • 在阅读 RTOS LiteOS 内核源码时发现该内核使用的链表时通用链表,而 FreeRTOS 内核使用的时非通用链表,所以,有必要发布一下关于链表实现的笔记。
  • 以下内容为个人笔记,涉及一些非专业词汇,敬请谅解,谢谢。

链接

参考

  • 上面链接
  • FreeRTOS 内核源码

头文件 lssList.h

/**
  ******************************************************************************
  * @file    comList.h
  * @author  lzm
  * @version V1.0
  * @date    2020-09-26
  * @brief   参考FreeRTOS
  * @attention
  *
  * 实验平台:LZM
  * 
  ******************************************************************************
  */
#ifndef  _LSS_LIST_H_
#define _LSS_LIST_H_

#include "LssAppConfig.h"


/*
*********************************************************************************************************
*                                          CONFIG
*********************************************************************************************************
*/
#define lssLIST_MAX_VALUE 0XFFFFFFFF
#define lssLIST_BASE_TYPE unsigned long



/*
*********************************************************************************************************
*                                          STRUCT
*********************************************************************************************************
*/

/*
 * The linked list node
 */
struct LIST_ITEM_LSS_T
{
    uint32_t xItemValue; // 记号值
    
    struct LIST_ITEM_LSS_T * pxNext; // 上一个
	struct LIST_ITEM_LSS_T  * pxPrevious; // 下一个
    
    void * pvOwner; // 挂钩
	void * pvContainer; // 归属
};
typedef struct LIST_ITEM_LSS_T listItem_t;

/*
 * Linked list mini node
 */
struct LIST_MINI_ITEM_LSS_T
{
    uint32_t xItemValue; // 记号值(跟节点,一般为最大)
    
	struct LIST_ITEM_LSS_T * pxNext;
	struct LIST_ITEM_LSS_T * pxPrevious;
};
typedef struct LIST_MINI_ITEM_LSS_T listMiniItem_t;

/*
 * The linked list (or root node)
 */
struct LIST_LSS_T
{
    uint32_t uxNumberOfItems; // 节点总数(忽略根节点)
    
    struct LIST_ITEM_LSS_T * pxIndex; // 链表索引
    struct LIST_MINI_ITEM_LSS_T xListEnd; // 链表根节点
};
typedef struct LIST_LSS_T list_t;
/*
*********************************************************************************************************
*                                          FUNCTION
*********************************************************************************************************
*/
void listInit(list_t * const list);
void listItemInit(listItem_t * const item);
void listInsertEnd( list_t * const pxList, listItem_t * const pxNewListItem );
void listInsert( list_t * const pxList, listItem_t * const pxNewListItem );
uint32_t listRemove( listItem_t * const pxItemToRemove );
/*
*********************************************************************************************************
*                                          API
*********************************************************************************************************
*/
/* 配对挂钩与袜子 */ 
#define lssSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) \
           ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) ) 

/* 获取袜子 */ 
#define lssGET_LIST_ITEM_OWNER( pxListItem ) \
            ( ( pxListItem )->pvOwner )

/* 设置记号值 */  
#define lssSET_LIST_ITEM_VALUE( pxListItem, xValue ) \
   ( ( pxListItem )->xItemValue = ( xValue ) ) 

/* 获取记号值 */ 
#define lssGET_LIST_ITEM_VALUE( pxListItem ) \
   ( ( pxListItem )->xItemValue ) 

/* 获取第一个节点的节点值(*第一个节点和根节点是两回事*)*/ 
#define lssGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) \
   ( ( ( pxList )->xListEnd ).pxNext->xItemValue ) 

/* 获取链表的入口节点 */ 
#define lssGET_HEAD_ENTRY( pxList ) \
   ( ( ( pxList )->xListEnd ).pxNext ) 

/* 获取下一个节点 */ 
#define lssGET_NEXT( pxListItem ) \
   ( ( pxListItem )->pxNext ) 

/* 获取链表最后一个节点:头节点 */ 
#define lssGET_END_MARKER( pxList ) \
   ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/* 判断链表是否为空 */ 
#define lssLIST_IS_EMPTY( pxList ) \
   ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) ) 
   
   

/* 获取链表当前节点总数 */ 
#define lssCURRENT_LIST_LENGTH( pxList ) \
   ( ( pxList )->uxNumberOfItems ) 

/* 获取链表索引指向的下一个挂钩 */ 
#define lssGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )      \
{                       \
    list_t * const pxConstList = ( pxList );             \                                         \
    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                  \
    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )  \
    {                     \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;       \
    }                                                            \
    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;\
    } \
}

#endif

源文件 lssList.c

/**
  ******************************************************************************
  * @file    lssList.c
  * @author  lzm
  * @version V1.0
  * @date    2020-09-26
  * @brief    参考FreeRTOS
  *                 双链表
  * @attention
  *
  * 实验平台:LZM
  * 
  ******************************************************************************
  */

#include "lssList.h"

 /**
  * @brief  链表初始化
  * @param 
  * @retval 
  * @author lzm
  */
void listInit(list_t * const list)
{
    /* 索引指向最后:尾就是头 */
    list->pxIndex = (listItem_t *) &(list->xListEnd);
    
    /* 链表最大值 */
    list->xListEnd.xItemValue = lssLIST_MAX_VALUE;
    
    list->xListEnd.pxNext = ( listItem_t * ) &( list->xListEnd );
    list->xListEnd.pxPrevious = ( listItem_t * ) &( list->xListEnd );
    
    list->uxNumberOfItems = (lssLIST_BASE_TYPE)0U;
}

 /**
  * @brief  节点初始化
  * @param 
  * @retval 
  * @author lzm
  */
void listItemInit(listItem_t * const item)
{
    item->pvContainer = NULL;
}

/**
* @brief  插入链表尾部(*双向链表没有绝对的头尾,此处是以游标为参考物*)
* @param 
* @retval 
* @author lzm
*/
void listInsertEnd( 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;

	/* Remember which list the item is in. */
	pxNewListItem->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}

/**
* @brief  按记号值值插入
* @param 
* @retval 
* @author lzm
*/
void listInsert( list_t * const pxList, listItem_t * const pxNewListItem )
{
    listItem_t *pxIterator;
    const lssLIST_BASE_TYPE xValueOfInsertion = pxNewListItem->xItemValue; // 获取新节点记号值
    
    /* 按顺序寻找 */
	if( xValueOfInsertion == lssLIST_MAX_VALUE )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
	}
	else
	{
		for( pxIterator = ( listItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
		{
			/* There is nothing to do here, just iterating to the wanted
			insertion position. */
		}
	}

	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;

	/* Remember which list the item is in.  This allows fast removal of the
	item later. */
	pxNewListItem->pvContainer = ( void * ) pxList;

	( pxList->uxNumberOfItems )++;
}

/**
* @brief  从链表中删除节点
* @param 
* @retval 
* @author lzm
*/

uint32_t listRemove( listItem_t * const pxItemToRemove )
{
/* The list item knows which list it is in.  Obtain the list from the list
item. */
    list_t * const pxList = ( list_t * ) pxItemToRemove->pvContainer;

	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	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;
}
posted @ 2020-10-10 14:56  李柱明  阅读(275)  评论(0编辑  收藏  举报