数据结构中链表的实现以及排序

文章目录

  • 前言
  • 一、链表结构体定义
  • 二、具体实现过程
  • 三、排序方法
    • 1. 冒泡排序
    • 2. 选择排序
    • 3. 判断一个链表是否有环
  • 总结


前言


本期和大家主要分享的是关于数据结构中双向链表的实现过程,那么话不多说,来具体看看吧!

一、链表结构体定义

来分析一下,这里呢定义了一个int的数据类型,表明整个链表存放的是整形的数据;其次定义了链表节点的数据类型,其中包括了此节点存放的数据以及链接向下一个节点的地址;最主要的呢我们的链表是有头的(且链表类型结构体中存放了当前链表中的元素),并且链表头(链表类型,并不是一个节点)后的第一个节点是空节点,我们的有效节点是从这个空节点后面的这个节点开始存放数据的;

#ifndef __LINKLIST_H__
#define __LINKLIST_H__

#include 
#include 
#include 
/* 存储数据的类型 */
typedef int DataType;

/* 链表节点类型 */
typedef struct node
{
	DataType Data;			//数据域
	struct node *pNext;		//指向下一个节点的指针
}LinkNode;

/* 链表表头类型 */
typedef struct list
{
	LinkNode *pHead;
	int clen;
}LinkList;

extern LinkList *CreateLinkList(void);
extern LinkList *InsertHeadLinkList(LinkList *pTmpList, DataType TmpData);
extern int ShowLinkList(LinkList *pTmpList);
extern LinkNode *SearchLinkList(LinkList *pTmpList, DataType TmpData);
extern int UpdateLinkList(LinkList *pTmpList, DataType OldData, DataType NewData);
extern int InsertTailLinkList(LinkList *pTmpList, DataType TmpData);
extern int DeleteLinkList(LinkList *pTmpList, DataType TmpData);
extern int DestroyLinkList(LinkList **ppTmpList);
extern LinkNode *FindMidLinkNode(LinkList *pTmpList);
extern int ReverseLinkList(LinkList *pTmpList);
extern int BubbleSort(LinkList *pTmpList);
extern int ChoiceSortLinkList(LinkList *pTmpList);
#endif

二、具体实现过程

代码如下(示例):

#include "linklist.h"
/* 创建链表 */
LinkList *CreateLinkList(void)
{
	LinkList *pTmpList = NULL

	pTmpList = malloc(sizeof(LinkList));
	if (NULL == pTmpList)
	{
		perror("fail to malloc");
		return NULL;
	}

	pTmpList->clen = 0;
	pTmpList->pHead = malloc(sizeof(LinkNode));
	if (pTmpList->pHead == NULL)
	{
		perror("fail to malloc");
		return NULL;
	}

	pTmpList->pHead->pNext = NULL;

	return pTmpList;
}
/* 头插法插入数据 */
LinkList *InsertHeadLinkList(LinkList *pTmpList, DataType TmpData)
{
	LinkNode *pTmpNode = NULL;

	pTmpNode = malloc(sizeof(LinkNode));
	if (NULL == pTmpNode)
	{
		perror("fail to malloc");
		return NULL;
	}

	pTmpNode->Data = TmpData;
	pTmpNode->pNext = pTmpList->pHead->pNext;
	pTmpList->pHead->pNext = pTmpNode;
	pTmpList->clen++;

	return pTmpList;
}
/* 链表遍历 */
int ShowLinkList(LinkList *pTmpList)
{
	LinkNode *pTmpNode = NULL;

	pTmpNode = pTmpList->pHead->pNext;
	while (pTmpNode != NULL)
	{
		printf("%d ", pTmpNode->Data);
		pTmpNode = pTmpNode->pNext;
	}
	putchar('\n');

	return 0;
}
/* 查找元素 */
LinkNode *SearchLinkList(LinkList *pTmpList, DataType TmpData)
{
	LinkNode *pTmpNode = NULL;
	pTmpNode = pTmpList->pHead->pNext;

	while (pTmpNode != NULL)
	{
		if (pTmpNode->Data == TmpData)
		{
			return pTmpNode;
		}
		pTmpNode = pTmpNode->pNext;
	}
	
	return NULL;
}
/* 修改元素 */
int UpdateLinkList(LinkList *pTmpList, DataType OldData, DataType NewData)
{
	LinkNode *pTmpNode = NULL;
	pTmpNode = pTmpList->pHead->pNext;
	
	while (pTmpNode != NULL)
	{
		if (pTmpNode->Data == OldData)
		{
			pTmpNode->Data = NewData;
		}
		pTmpNode = pTmpNode->pNext;
	}

	return 0;
}
/* 尾插法插入元素 */
int InsertTailLinkList(LinkList *pTmpList, DataType TmpData)
{
	LinkNode *pTmpNode = NULL;
	LinkNode *pptmNode = NULL;
	pTmpNode = pTmpList->pHead;

	pptmNode = malloc(sizeof(LinkNode));
	if (pptmNode == NULL)
	{
		perror("fail to malloc");
		return -1;
	}

	while (pTmpNode->pNext != NULL)	//访问NULL的空间会段错误,这个就是第一个节点存在的好处
	{
		pTmpNode = pTmpNode->pNext;			//跳出后为最后一个节点
	}

	pptmNode->Data = TmpData;
	pTmpNode->pNext = pptmNode;
	pptmNode->pNext = NULL;
	pTmpList->clen++;

	return 0;
}
/* 删除一个链表节点(所有相同的元素都删除) */
int DeleteLinkList(LinkList *pTmpList, DataType TmpData)
{
	LinkNode *preLinkNode = NULL;
	LinkNode *desLinkNode = NULL;
	
	preLinkNode = pTmpList->pHead;
	desLinkNode = pTmpList->pHead->pNext;

	while (desLinkNode != NULL)
	{
		if (desLinkNode->Data == TmpData)
		{
			preLinkNode->pNext = desLinkNode->pNext;
			free(desLinkNode);
			desLinkNode = preLinkNode->pNext;
			pTmpList->clen--;
		}
		else
		{
			preLinkNode = preLinkNode->pNext;
			desLinkNode = desLinkNode->pNext;
		}	
	}

	return 0;
}
/* 销毁链表 */
int DestroyLinkList(LinkList **ppTmpList)
{
	LinkNode *pFreeNode = NULL;
	LinkNode *pTmpNode = NULL;

	pFreeNode = (*ppTmpList)->pHead;
	pTmpNode = (*ppTmpList)->pHead;

	while (pTmpNode != NULL)
	{
		pTmpNode = pTmpNode->pNext;
		free(pFreeNode);
		pFreeNode = pTmpNode;
	} 

	free(*ppTmpList);
	*ppTmpList = NULL;

	return 0;
}
/* 以下为链表的高级操作 */
/* 查找中间节点 */
LinkNode *FindMidLinkNode(LinkList *pTmpList)
{
	LinkNode *pFast = NULL;
	LinkNode *pSlow = NULL;

	pFast = pTmpList->pHead->pNext;
	pSlow = pTmpList->pHead->pNext;

	while (pFast != NULL)
	{
		pFast = pFast->pNext;
		if (NULL == pFast)
		{
			break;
		}
		pFast = pFast->pNext;			//快指针走两步(分两步,防止出现非法访问地址)
		if (NULL == pFast)
		{
			break;
		}
		pSlow = pSlow->pNext;			//慢指针走一步
	}
	
	return pSlow;
}
/* 链表倒置(头插法) */
/* 将链表断开,再次用头插法插入即可实现链表倒置 */
int ReverseLinkList(LinkList *pTmpList)
{
	LinkNode *pTmpNode = NULL;
	LinkNode *pInsertNode = NULL;

	pTmpNode = pTmpList->pHead->pNext;
	pTmpList->pHead->pNext = NULL;
	
	while (pTmpNode != NULL)
	{
		pInsertNode = pTmpNode;
		pTmpNode = pTmpNode->pNext;
		pInsertNode->pNext = pTmpList->pHead->pNext;
		pTmpList->pHead->pNext = pInsertNode;
	}
	return 0;
}

三、排序方法

这里给出两种排序方法,可能大家用c语言实现排序的时候比较简单,但是过渡到数据结构会有一点难度,这是没有关系的,主要是多画图多理解多思考;几遍下来比较难的问题就会变得容易许多;

1. 冒泡排序

/* 冒泡排序(最后一次不需要进行比较) */
int BubbleSort(LinkList *pTmpList)
{
	LinkNode *preTmpNode = NULL;
	LinkNode *deTmpNode = NULL;
	LinkNode *pEndTmpNode = NULL;
	DataType TmpData = 0;

	preTmpNode = pTmpList->pHead->pNext;				 //前一个指向第一个节点
	if (preTmpNode == NULL || preTmpNode->pNext == NULL) //第一个节点没存数据或者只有第一个节点存储了数据不用排序
	{
		return 0;
	}

	deTmpNode = preTmpNode->pNext;						//后一个指针指向第一个指针的下一个节点

	while (deTmpNode != pEndTmpNode)					//前一个指针和后一个指针不是同一个节点,pEndTmpNode为每次比较后的最后一个节点
	{
		while (deTmpNode != pEndTmpNode)
		{
			if (preTmpNode->Data > deTmpNode->Data)
			{
				TmpData = preTmpNode->Data;
				preTmpNode->Data = deTmpNode->Data;
				deTmpNode->Data = TmpData;
			}
			preTmpNode = preTmpNode->pNext;
			deTmpNode = deTmpNode->pNext;
		}
		pEndTmpNode = preTmpNode;
		preTmpNode = pTmpList->pHead->pNext;
		deTmpNode = preTmpNode->pNext;
	}
	return 0;
}

2. 选择排序

/* 选择排序 */
int ChoiceSortLinkList(LinkList *pTmpList)
{
	LinkNode *pMinNode = NULL;		//每轮找出最小的一个,与pSwapNode交换值
	LinkNode *pTmpNode = NULL;		//每次从 pSwapNode的后一个开始往后寻找最小的数(与pMinNode比较)
	LinkNode *pSwapNode = NULL;		//每次寻找的开头(前面已经找好最小的数排列完毕)
	DataType TmpData;

	if (pTmpList->pHead->pNext == NULL || pTmpList->pHead->pNext->pNext == NULL)	//如果空节点后面的第一个节点无元素或者之后的第二个节点无元素(全部链表只有一个元素)则不用排序
	{
		return 0;
	}

	pSwapNode = pTmpList->pHead->pNext;

	while (pSwapNode->pNext != NULL)
	{
		pMinNode = pSwapNode;			//每轮开始从 pSwapNode开始
		pTmpNode = pSwapNode->pNext;	//从后一个往后开始比较寻找比最小的还小的
		while (pTmpNode != NULL)
		{
			if (pTmpNode->Data < pMinNode->Data)
			{
				pMinNode = pTmpNode;		//找到后将最小的地址赋值给 pMinNode
			}
			pTmpNode = pTmpNode->pNext;		//接着往后找
		}

		if (pMinNode != pSwapNode)			//如果最小的不是第一个就交换,若是第一个则不用进行操作
		{
			TmpData = pMinNode->Data;
			pMinNode->Data = pSwapNode->Data;
			pSwapNode->Data = TmpData;
		}
		pSwapNode = pSwapNode->pNext;		//此位置已经排列完毕,开始从下一个位置开始
	}

	return 0;
}

3. 判断一个链表是否有环

/* 如何判断一个链表是否有环(用快慢指针的方法) */
int IsCircleLinkList(LinkList *pTmpList, int *pn, LinkNode *ppNode)		//未理解
{
	LinkNode *pFast = NULL;
	LinkNode *pSlow = NULL;
	LinkNode *pTmpNode = NULL;
	int cnt = 1;

	pFast = pTmpList->pHead->pNext;
	pSlow = pTmpList->pHead->pNext;

	while (pFast != NULL)
	{
		pFast = pFast->pNext;
		if (NULL == pFast)
		{
			return 0;
		}
		pFast = pFast->pNext;
		if (NULL == pFast)
		{
			return 0;
		}

		pSlow = pSlow->pNext;
		if (pFast == pSlow)
		{

			pTmpNode = pSlow->pNext;
			while (pTmpNode != pSlow)
			{
				cnt++;
				pTmpNode = pTmpNode->pNext;
			}

			*pn = cnt;

			pFast = pTmpList->pHead->pNext;
			while (1)
			{
				pSlow = pSlow->pNext;
				pFast = pFast->pNext;

				if (pSlow == pFast)
				{
					*ppNode = pSlow;
					break;
				}
			}

			return 1;
		}
	}

	return 0;
}

总结

链表的优点:原则上只要系统的内存足够大,那么链表能够进行无限存储;而且存一个申请一个,不会提前占用空间,它是一种空间上不连续的存储方式;

本期的分享就到这里结束啦,总结一下,链表是必须掌握的一种数据结构,是闭着眼睛都要能写出来的一种数据结构,所以必须多练习,多思考;
最后,各位小伙伴们如果喜欢我的分享可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

你可能感兴趣的:(数据结构,链表,数据结构,算法,arm开发,linux)