單鏈表和數組的比較
單鏈表
1. 在內存中,節點的地址空間不連續;
2. 增、刪數據相對容易,只需要知道要增加、刪除的位置,可以不操作其他額外的元素即可實現;
3. 因爲不可以通過隨機讀取鏈表,故查找效率相對較低;
4. 不用指定大小,擴展方便;
數組
1. 在內存中,元素的地址空間連續;
2. 需要在程序開始運行時預分配好空間,可能會存在內存空間的浪費;
3. 插入和刪除數據效率低,增刪數據時,被操作數據後面的數據都需要移動;
4. 隨機讀取效率高,因爲數組是連續的內存空間,所以可以直接使用數組下表訪問對應的數據;
5. 不利於擴展,空間不夠時,需要重新定義數組;
各自的優缺點
1. 數組優點:①、數組內的數據可以隨機訪問; ②、數據查找效率較高(內存連續);
2. 鏈表優點:①、方便數據的刪除、插入; ②、長度可變,擴展性好; ③、內存利用率高(可以不連續);
鏈表在項目中的使用
基本數據結構
typedef unsigned char LFP_UINT8;
typedef unsigned short LFP_UINT16;
typedef unsigned int LFP_UINT32;
typedef unsigned long long LFP_UINT64;
typedef char LFP_INT8;
typedef short LFP_INT16;
typedef int LFP_INT32;
typedef long long LFP_INT64;
typedef long LFP_LONG;
typedef void LFP_VOID;
#define LFP_BOOL LFP_INT32
#define LFP_OK (0)
#define LFP_ERR (-1)
#define LFP_NULL (NULL)
鏈表數據結構
/*single list structure definition */
typedef struct lfp_single_list_t
{
LFP_INT32 data;
struct lfp_single_list_t *pNext;
}LFP_SINGLE_LIST_T;
鏈表實現過程
鏈表主要涉及創建、添加、查找、插入、刪除、銷燬等幾個點,下面分述這些過程(查找過程不顯式描述)
創建(帶頭節點)
僞代碼
- 因爲需要修改頭節點(指針)的指向,所以需要傳入指針的地址,也即二維指針;
create(list **ppList)
{
*ppList = (list *)malloc(sizeof(list));
*ppList->data = 0;
*ppList->pNext = NULL;
}
添加(尾部添加)
僞代碼
- 使用pWalk->pNext而不是pWalk去遍歷鏈表,省去記錄前驅節點,避免尾部添加時,需要二次遍歷;
add(list *pList, data_t data)
{
...
assert(pList);
pWalk = pList;
while(pWalk->pNext)
{
pWalk = pWalk->pNext;
}
pNewNode = (list *)malloc(sizeof(list));
...
pWalk->pNext = pNewNode;
}
插入(在某指定節點之前插入)
僞代碼
- 插入有多種方式,例如在指定的位置插入,指定某節點插入等,這裏介紹以某指定的節點插入
insert(list *pList, list *pNode)
{
...
assert(pList);
pWalk = pList;
while(pWalk->pNext)
{
if(pWalk->pNext == pNode)
{
break;
}
pWalk = pWalk->pNext;
}
if(!pWalk->pNext)
{
return err;
}
pNewNode = (list *)malloc(sizeof(list));
pNewNode->pNext = pWalk->pNext;
pWalk->pNext = pNewNode;
}
刪除(刪除某個指定的節點)
僞代碼
- 將指定的節點從鏈表中刪除,釋放先前分配的存儲空間
delete(list *pList, list *pDelNode)
{
...
assert(pList);
pWalk = pList;
while(pWalk->pNext)
{
if(pWalk->pNext == pDelNode)
{
break;
}
pWalk = pWalk->pNext;
}
if(!pWalk->pNext)
{
return err;
}
pWalk->pNext = pWalk->pNext->pNext; /* 無論pwalk->pNext->pNext是否爲空,都可以表示 */
}
銷燬(和create結對,銷燬鏈表時)
僞代碼
- 傳入頭節點的地址
destroy(list *ppList)
{
...
assert(pplist && *ppList);
pWalk = *ppList;
while(pWalk)
{
pTmp = pWalk;
pWalk = pWalk->pNext;
free(pTmp);
}
*pList = (list *)NULL;
}
- 不傳入頭節點的地址
destroy(list *pList)
{
...
assert(pList);
pWalk = pList;
while(pWalk)
{
pTmp = pWalk;
pWalk = pWalk->pNext;
free(pTmp);
}
}
此時如果有一個鏈表pHead,以此方式銷燬鏈表時,應:
destroy(pList);
pHead = NULL;/* 將頭節點指向空地址,避免使用pHead仍然可以訪問已經釋放的鏈表 */
鏈表相關完整源碼(含測試)
/************************************************************************************
File name: lfp_single_list.c
Description: Single linked list module implementation.
Author: wytaitaislee
Version: V1.0.0
Date: 2019-11-17
History: 1. create file. -- 2019-11-17
************************************************************************************/
#include "lfp_single_list.h"
#define LFP_SINGLE_LIST_NODE_MALLOC(ppNode) \
do \
{ \
*ppNode = (LFP_SINGLE_LIST_T *)LFP_MALLOC(sizeof(LFP_SINGLE_LIST_T)); \
(*ppNode)->pNext = LFP_NULL; \
(*ppNode)->data = 0; \
}while(0);
#define LFP_SINGLE_LIST_NODE_FREE(pNode) \
do \
{ \
pNode->pNext = LFP_NULL; \
pNode->data = 0; \
pNode = LFP_NULL; \
}while(0);
/*@fn LFP_INT32 lfp_single_list_create_head(LFP_SINGLE_LIST_T** ppList)
* @brief create the head node of single list
* @param[in] the ptr of the head ptr whom pointer to the single list
* @param[out] the same as param[in]
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_create_head(LFP_SINGLE_LIST_T **ppList)
{
LFP_ASSERT_ERR_RET(ppList);
LFP_SINGLE_LIST_NODE_MALLOC(ppList);
LFP_ASSERT_ERR_RET(*ppList);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_add_element(LFP_SINGLE_LIST_T *pHead, LFP_UINT32 uiNum)
* @brief add a specific num of nodes to the end of the single list
* @param[in] LFP_SINGLE_LIST_T *pHead - the head of the list
* @param[in] LFP_UINT32 uiNum - the num of the specific nodes
* @param[out] NULL
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_add_element(LFP_SINGLE_LIST_T *pList, LFP_UINT32 uiNum)
{
LFP_SINGLE_LIST_T *pWalk = LFP_NULL;
LFP_SINGLE_LIST_T *pNode = LFP_NULL;
LFP_UINT32 uiAddCnt = 0;
LFP_ASSERT_ERR_RET(pList);
pWalk = pList;
/* move to the end of the list */
while(pWalk->pNext)
{
pWalk = pWalk->pNext;
}
/* add uiNum's of node to the list */
for(uiAddCnt = 0; uiAddCnt < uiNum; uiAddCnt++)
{
LFP_SINGLE_LIST_NODE_MALLOC(&pNode);
pWalk->pNext = pNode;
pWalk = pWalk->pNext;
LFP_SINGLE_LIST_CRIT("add node[%p] to the list ok!\n", pNode);
}
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_append_node(LFP_SINGLE_LIST_T *pList, LFP_SINGLE_LIST_T *pAddNode)
* @brief append a new node to the end of the single list
* @param[in] LFP_SINGLE_LIST_T *pList - the head of the list
* @param[in] LFP_SINGLE_LIST_T *pAddNode - the node to be added
* @param[out] LFP_NULL
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_append_node(LFP_SINGLE_LIST_T *pList, LFP_SINGLE_LIST_T *pAddNode)
{
LFP_SINGLE_LIST_T *pWalk = LFP_NULL;
LFP_ASSERT_ERR_RET(pList && pAddNode);
pWalk = pList;
/* move to the end of the list */
while(pWalk->pNext)
{
pWalk = pWalk->pNext;
}
pWalk->pNext = pAddNode;
LFP_SINGLE_LIST_CRIT("append node[%p] to the list ok!\n", pAddNode);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_insert_element_by_node( LFP_SINGLE_LIST_T *pList,
LFP_SINGLE_LIST_T *pPrev,
LFP_INT32 iData)
* @brief add a new node to the single list(before a specific node)
* @param[in] LFP_SINGLE_LIST_T *pList - the head of list
* @param[in] LFP_SINGLE_LIST_T *pPrev - the previous element of the inserted element
* @param[in] LFP_INT32 iData - the data of the new node
* @param[out] LFP_NULL
* @note if *pNode does not exist in the list, return LFP_ERR
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_insert_element_by_node(LFP_SINGLE_LIST_T *pList, LFP_SINGLE_LIST_T *pNode, LFP_INT32 iData)
{
LFP_SINGLE_LIST_T *pWalk = LFP_NULL;
LFP_SINGLE_LIST_T *pNewNode = LFP_NULL;
LFP_ASSERT_ERR_RET(pList && pNode);
pWalk = pList;
/* here we use pWalk->pNext to avoid traverse to the end */
while(pWalk->pNext)
{
if(pWalk->pNext == pNode)
{
break;
}
pWalk = pWalk->pNext;
}
if(!pWalk->pNext)
{ /* insert to the end of the list. */
LFP_SINGLE_LIST_ERR("there is no node[%p][data:%d] in the list\n", pNode, pNode->data);
return LFP_ERR;
}
LFP_SINGLE_LIST_NODE_MALLOC(&pNewNode);
LFP_ASSERT_ERR_RET(pNewNode);
pNewNode->pNext = pWalk->pNext;
pWalk->pNext = pNewNode;
LFP_SINGLE_LIST_CRIT("add node[%p] to the list ok!\n", pNewNode);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_insert_element_by_pos( LFP_SINGLE_LIST_T *pList,
LFP_INT32 iPos,
LFP_INT32 iData)
* @brief add a new node to the single list(before a specific position)
* @param[in] LFP_SINGLE_LIST_T *pList - the head of list
* @param[in] LFP_INT32 iPos - the specific position
* @param[in] LFP_INT32 iData - the data of the new node
* @param[out] LFP_NULL
* @note if the length of the list is smaller than iPos, add a new node at the end of the list
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_insert_element_by_pos(LFP_SINGLE_LIST_T *pList, LFP_INT32 iPos, LFP_INT32 iData)
{
LFP_SINGLE_LIST_T *pWalk = LFP_NULL;
LFP_SINGLE_LIST_T *pNewNode = LFP_NULL;
LFP_INT32 iWalkCnt = 0;
LFP_ASSERT_ERR_RET(pList);
pWalk = pList;
/* here we use pWalk->pNext to avoid traverse to the end */
while(pWalk->pNext)
{
if(!pWalk->pNext)
{
break;
}
/* if iPos < 0, add the node to the end */
if(iPos >= 0 && iWalkCnt >= iPos)
{
break;
}
iWalkCnt++;
pWalk = pWalk->pNext;
}
/* Whether inserted in the middle or at the end, it is compatible */
LFP_SINGLE_LIST_NODE_MALLOC(&pNewNode);
LFP_ASSERT_ERR_RET(pNewNode);
pNewNode->data = iData;
pNewNode->pNext = pWalk->pNext; /*if pWalk is the last ,pWalk->pNext must be LFP_NULL */
pWalk->pNext = pNewNode;
LFP_SINGLE_LIST_CRIT("add node[%p] to the list ok!\n", pNewNode);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_delete_element(LFP_SINGLE_LIST_T *pList, LFP_SINGLE_LIST_T *pNode)
* @brief delete a node from the list
* @param[in] LFP_SINGLE_LIST_T *pList - the head of list
* @param[in] LFP_SINGLE_LIST_T *pNode - the element to be deleted
* @param[out] NULL
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_delete_element(LFP_SINGLE_LIST_T *pList, LFP_SINGLE_LIST_T *pDelNode)
{
LFP_SINGLE_LIST_T *pWalk = LFP_NULL;
LFP_ASSERT_ERR_RET(pList && pDelNode);
pWalk = pList;
while(pWalk->pNext)
{
if(pWalk->pNext == pDelNode)
{
break;
}
pWalk = pWalk->pNext;
}
if(!pWalk->pNext)
{
LFP_SINGLE_LIST_CRIT("there is no node[%p][data:%d] in the list\n", pDelNode, pDelNode->data);
return LFP_OK; /* default delete ok .*/
}
pWalk->pNext = pWalk->pNext->pNext;
LFP_SINGLE_LIST_CRIT("delete node[%p] from the list ok!\n", pDelNode);
LFP_SINGLE_LIST_NODE_FREE(pDelNode);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_destroy(LFP_SINGLE_LIST_T **pList)
* @brief destroy the list
* @param[in] LFP_SINGLE_LIST_T *pList - the head of the list
* @param[out] LFP_NULL
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_destroy(LFP_SINGLE_LIST_T **ppList)
{
LFP_SINGLE_LIST_T* pTmp = LFP_NULL;
LFP_SINGLE_LIST_T* pWalk = LFP_NULL;
LFP_ASSERT_ERR_RET(ppList && *ppList);
pWalk = *ppList;
while(pWalk)
{
pTmp = pWalk;
pWalk = pWalk->pNext;
LFP_SINGLE_LIST_NODE_FREE(pTmp);
}
*ppList = (LFP_SINGLE_LIST_T*)LFP_NULL;
return LFP_OK;
}
/*@fn LFP_STATIC LFP_INT32 lfp_single_list_module_test(LFP_VOID)
* @brief test entrance for the single list module.
* @param[in] LFP_VOID
* @param[out] NULL
* @return LFP_OK/LFP_ERR
*/
LFP_STATIC LFP_INT32 lfp_single_list_module_test(LFP_VOID)
{
LFP_INT32 iItem = 0;
LFP_INT32 iRet = LFP_OK;
LFP_SINGLE_LIST_T *pHead = LFP_NULL;
LFP_SINGLE_LIST_T *pNode = LFP_NULL;
LFP_SINGLE_LIST_T *pMid = LFP_NULL, *pTail = LFP_NULL;
pHead = pNode = pMid = pTail = LFP_NULL;
LFP_SINGLE_LIST_CRIT("start testing module %s \n", LFP_SINGLE_LIST_MODULE);
/* 1. create a head node */
if(LFP_OK != lfp_single_list_create_head(&pHead))
{
LFP_SINGLE_LIST_ERR("create list single head failed\n");
return LFP_ERR;
}
LFP_SINGLE_LIST_CRIT("the list head is[%p].\n", pHead);
/* 2. add LFP_SINGLE_LIST_ADD_ELEM element to the list */
if(LFP_OK != lfp_single_list_add_element(pHead, LFP_SINGLE_LIST_ADD_ELEM))
{
LFP_SINGLE_LIST_ERR("add element to the list failed, addnum = %d\n", LFP_SINGLE_LIST_ADD_ELEM);
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
pTail = pHead;
while(pTail->pNext)
{
if(iItem == LFP_SINGLE_LIST_ADD_ELEM / 2)
{
pMid = pTail->pNext;
LFP_SINGLE_LIST_CRIT("the middle element is[%p]!\n", pMid);
}
pTail = pTail->pNext;
iItem++;
}
LFP_SINGLE_LIST_CRIT("the tail element is[%p]!\n", pTail);
/* 3. insert a node to the end */
if(LFP_OK != lfp_single_list_add_element(pHead, 1))
{
LFP_SINGLE_LIST_ERR("insert a new node to the end err\n");
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
LFP_SINGLE_LIST_CRIT("add element to the end of th list success!\n");
/* 4. insert a node to the head */
if(LFP_OK != lfp_single_list_insert_element_by_pos(pHead, 0, 4*LFP_SINGLE_LIST_ADD_ELEM))
{
LFP_SINGLE_LIST_ERR("insert a to the head err\n");
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
LFP_SINGLE_LIST_CRIT("add element to the head of th list success!\n");
/* 5. insert a node to the mid */
if(LFP_OK != lfp_single_list_insert_element_by_node(pHead, pMid, 5*LFP_SINGLE_LIST_ADD_ELEM))
{
LFP_SINGLE_LIST_ERR("insert a node to the mid err\n");
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
LFP_SINGLE_LIST_CRIT("add element to the mid of th list success!\n");
LFP_ASSERT_ERR_RET(pHead);
pNode = pHead->pNext;
while(pNode)
{
LFP_SINGLE_LIST_CRIT("list element[%p]\n", pNode);
pTail = pNode;
pNode = pNode->pNext;
}
pNode = pHead->pNext;
/* 6. delete the end node of the list */
if(LFP_OK != lfp_single_list_delete_element(pHead, pTail))
{
LFP_SINGLE_LIST_ERR("delete a node[%p] err\n", pTail);
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
/* 7. delete the head node of the list */
if(LFP_OK != lfp_single_list_delete_element(pHead, pNode))
{
LFP_SINGLE_LIST_ERR("delete a node[%p] err\n", pNode);
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
/* 8. delete the middle node of the list */
if(LFP_OK != lfp_single_list_delete_element(pHead, pMid))
{
LFP_SINGLE_LIST_ERR("delete a node[%p] err\n", pMid);
iRet = LFP_ERR;
goto lfp_single_list_exit;
}
lfp_single_list_exit:
/* 9. destory the single list */
if(LFP_OK != lfp_single_list_destroy(&pHead))
{
LFP_SINGLE_LIST_ERR("destroy the single list err\n");
return LFP_ERR;
}
while(pHead)
{
LFP_SINGLE_LIST_ERR("list element[%p] still exist\n", pHead);
pHead = pHead->pNext;
}
LFP_SINGLE_LIST_CRIT("testing %s module ok!\n", LFP_SINGLE_LIST_MODULE);
return LFP_OK;
}
/*@fn LFP_INT32 lfp_single_list_module_test_init(LFP_VOID)
* @brief the single list test module main entrance.
* @param[in] LFP_VOID
* @param[out] NULL
* @return LFP_OK/LFP_ERR
*/
LFP_INT32 lfp_single_list_module_test_init(LFP_VOID)
{
LFP_MODULES_REGISTER_SIGN(LFP_SINGLE_LIST_CRIT, LFP_SINGLE_LIST_SIGN_OK);
lfp_single_list_module_test();
return LFP_OK;
}