数据结构与算法(C)—单链表

数据结构与算法—单链表

  • 一、单链表定义
  • 二、单链表插入
  • 三、单链表查找
  • 四、单链表反转
  • 五、单链表是否有环
  • 六、两个单链表是否相交
  • 七、删除链表重复元素
  • 八、测试代码

本文变量命名前缀:

  1. 全局变量:g_
  2. 数组:a
  3. 指针:p
  4. 结构体:st
  5. unsigned int:ui

本文代码可以到Github下载:https://github.com/liyuewu-github/DataStructure

一、单链表定义

/* 单链表 */
typedef struct S_List
{
	unsigned int uiValue;
	struct S_List *pstNext;
}S_LIST_S;

二、单链表插入

链表插入可用于构建链表。

/* 链表插入 */
S_LIST_S * SLIST_Insert(S_LIST_S *pstSList, unsigned int uiValue)
{
	S_LIST_S *pstSList_New;
	S_LIST_S *pstSList_Iter;

	pstSList_New = malloc(sizeof(S_LIST_S));
	if (!pstSList_New)
		return;

	pstSList_New->uiValue = uiValue;
	pstSList_New->pstNext = NULL;

	if (!pstSList) /* 链表第一个节点 */
	{
		pstSList = pstSList_New;
		return pstSList;
	}

	pstSList_Iter = pstSList;
	while (pstSList_Iter->pstNext)
	{
		pstSList_Iter = pstSList_Iter->pstNext;
	}
	
	pstSList_Iter->pstNext = pstSList_New;

	return pstSList;
}

三、单链表查找

根据Key查找链表节点。

/* 查找链表 */
S_LIST_S * SLIST_Find(S_LIST_S *pstSList, unsigned int uiValue)
{
	while (pstSList)
	{	
		if (pstSList->uiValue == uiValue)
			return pstSList;
		pstSList = pstSList->pstNext;
	}

	return NULL;
}

查找倒数第K个节点。
定义两个链表节点,其中一个先走K步,另一个再走,快的走到尾节点,则慢点走到倒数第K个节点。

/* 找到链表倒数第K个节点 */
S_LIST_S *SLIST_Find_K(S_LIST_S *pstSList, unsigned int uiK)
{
	S_LIST_S *pstFast = pstSList;
	S_LIST_S *pstSlow = pstSList;

	if(!pstSList)
		return NULL;

	while(pstFast->pstNext)
	{
		if(--uiK > 0)
			pstFast = pstFast->pstNext;
		pstFast = pstFast->pstNext;
		pstSlow = pstSlow->pstNext;
	}

	return pstSlow;
}

四、单链表反转

依次执行后一个节点指向前一个节点。

/* 链表反转-非递归 */
S_LIST_S *SLIST_Reverse_NoRecursive(S_LIST_S *pstSList)
{
	S_LIST_S *pstSList_Rev = NULL;
	S_LIST_S *pstSList_Cur;
	S_LIST_S *pstSList_Next;

	pstSList_Cur = pstSList;

	while (pstSList_Cur)
	{
		pstSList_Next = pstSList_Cur->pstNext; /* 先记录当前节点的下一个节点,后面会被覆盖 */
		pstSList_Cur->pstNext = pstSList_Rev; /* 当前节点pstNext指向其前一个节点,即反转 */
		pstSList_Rev = pstSList_Cur; /* 当前节点作为下一轮的前一个节点 */
		pstSList_Cur = pstSList_Next; /* 当前节点pstNext作为下一轮的当前节点,继续遍历直至到链表尾 */
	}

	return pstSList_Rev;
}

五、单链表是否有环

定义两个链表节点,快的每次走2步,慢的走1步,如果两个节点在遍历中相等,说明链表有环。

/* 链表有没有环 */
int SLIST_IsRing(S_LIST_S *pstSList, S_LIST_S **ppstSList_Ring)
{
	S_LIST_S *pstSList_Fast = pstSList;
	S_LIST_S *pstSList_Slow = pstSList;
	*ppstSList_Ring = NULL;

	if ((!pstSList) || (!pstSList->pstNext)) /* 空链表和只有一个元素的链表不会有环 */
		return 0;

	while (pstSList_Slow && pstSList_Fast->pstNext) /* 能走到尾结点说明没环 */
	{
		pstSList_Fast = pstSList_Fast->pstNext->pstNext;
		pstSList_Slow = pstSList_Slow->pstNext;
		if (pstSList_Slow == pstSList_Fast)
		{
			*ppstSList_Ring = pstSList_Slow;
			return 1;
		}
	}
	return 0;
}

六、两个单链表是否相交

如果两个单链表相交,则其尾结点一定相等。

/* 链表是否相交 */
int SLIST_IsCross(S_LIST_S *pstSListA, S_LIST_S *pstSListB)
{
	if ((!pstSListA) || (!pstSListB))
		return 0;

	while (pstSListA->pstNext)
		pstSListA = pstSListA->pstNext;

	while(pstSListB->pstNext)
		pstSListB = pstSListB->pstNext;

	if (pstSListA == pstSListB) /* 如果两个单链表相交,则尾节点是一样的 */
		return 1;

	return 0;
}

七、删除链表重复元素

链表中Key值出现时记录到数组做标记,如果再次出现则说明是重复元素。

/* 链表删除重复元素 */
S_LIST_S * SLIST_Delete_Repect(S_LIST_S *pstSList)
{
	unsigned char aucList[1000] = {0};
	unsigned int uiValue;
	S_LIST_S *pstPrev;
	S_LIST_S *pstIter;
	
	if (!pstSList)
		return NULL;
	pstIter = pstSList;
	while (pstIter->pstNext)
	{
		uiValue = pstIter->uiValue;
		if (aucList[uiValue] > 0)
		{
			#ifdef DEBUG
			printf("value rep %d pre value %d\n",uiValue,pstPrev->uiValue);
			#endif
			free(pstPrev->pstNext);
			pstPrev->pstNext = pstPrev->pstNext->pstNext;
		}
		
		pstPrev = pstIter;
		pstIter = pstIter->pstNext;
		aucList[uiValue]++;
	}

	return pstSList;
}

八、测试代码

打印链表。

/* 打印链表 */
void SLIST_Dump(S_LIST_S *pstSList)
{
	while (pstSList)
	{
		printf("%d \n", pstSList->uiValue);
		pstSList = pstSList->pstNext;
	}
}

测试程序。

void main(void)
{
	unsigned int auiList[] = {1,3,7,5,7,9};
	unsigned int uiLen = sizeof(auiList)/sizeof(unsigned int);
	S_LIST_S *pstSList = NULL;
	int i;

	for (i = 0; i < uiLen; i++)
		pstSList = SLIST_Insert(pstSList, auiList[i]);
	
#ifdef LIST_REVERSE_TEST
	SLIST_Dump(pstSList);
	pstSList = SLIST_Reverse_NoRecursive(pstSList);
	SLIST_Dump(pstSList);
#endif

#ifdef LIST_K_TEST
	S_LIST_S * pstNodeK = SLIST_Find_K(pstSList, 3);
	printf("K %d\n", pstNodeK->uiValue);
#endif

#ifdef LIST_REPECT_TEST
	SLIST_Dump(pstSList);
	pstSList = SLIST_Delete_Repect(pstSList);
	SLIST_Dump(pstSList);
#endif

#ifdef LIST_RING_TEST
	S_LIST_S *pstSList_Ring;
	int iIsRing = SLIST_IsRing(pstSList,&pstSList_Ring);
	printf("isRing %d %p\n",iIsRing,pstSList_Ring);

	S_LIST_S * pstNode = SLIST_Find(pstSList,  3);
	S_LIST_S * pstIter = pstSList;
	while ( pstIter->pstNext)
		pstIter = pstIter->pstNext;
	pstIter->pstNext = pstNode;

	iIsRing = SLIST_IsRing(pstSList,&pstSList_Ring);
	if (iIsRing)
	{
		printf("isRing %d %d %d\n",iIsRing,pstSList_Ring->pstNext->uiValue,pstNode->uiValue);
	}
#endif

#ifdef LIST_CROSS_TEST
	unsigned int auiListB[] = {2,4,6,8};
	unsigned int auiListC[] = {1,2,3};
	unsigned int uiLenB = sizeof(auiListB)/sizeof(unsigned int);
	unsigned int uiLenC = sizeof(auiListC)/sizeof(unsigned int);
	S_LIST_S *pstSListB = NULL;
	S_LIST_S *pstSListC = NULL;
	int iIsCross;
	
	for (i = 0; i < uiLenB; i++)
		pstSListB = SLIST_Insert(pstSListB, auiListB[i]);

	for (i = 0; i < uiLenC; i++)
		pstSListC = SLIST_Insert(pstSListC, auiListC[i]);

	iIsCross = SLIST_IsCross(pstSListB, pstSListC);
	printf("isCross %d\n",iIsCross);
	
	S_LIST_S * pstIter = pstSListB;
	while ( pstIter->pstNext)
		pstIter = pstIter->pstNext;
	pstIter->pstNext = pstSList;

	pstIter = pstSListC;
	while ( pstIter->pstNext)
		pstIter = pstIter->pstNext;
	pstIter->pstNext = pstSList;

	iIsCross = SLIST_IsCross(pstSListB, pstSListC);
	printf("isCross %d\n",iIsCross);
#endif
	
	return;
}

你可能感兴趣的:(数据结构与算法(C语言))