单链表C语言实现,伪代码到完整模块

单链表C语言实现

单链表和数组的比较

单链表

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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章