IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构 — 单向链表 -> 正文阅读

[数据结构与算法]数据结构 — 单向链表

文章目录

目录

前言

单向链表

(1)单向不循环链表

? ? ? ?单向不循环链表的演示demo

(2)单向循环链表

单向循环链表的演示demo如下:

总结



前言

链表是什么?

????????链表是编程语言中常见的一种数据结构,它可以实现动态的创建和删除,只要内存足够,链表的数量和长度是可以无限多和无限长的。

????????链表顾名思义是一种链式的数据结构,它由一个个节点组成,并通过节点之间的互相关联链接,形成了类似一条链式的结构。

????????链表的节点一般可以分为数据域和指针域。数据域中是存放节点数据的,往往链表的节点都是结构体类型的,可以方便定义多种不同的数据类型,便于使用。指针域是存放节点的指针的,是链表中每个节点能互相串联起来的关键,这个至关重要!

????????一个链表节点的示意图如下:


温馨提示:以下是本篇文章正文内容。

单向链表

? ? ? ? 单向链表根据使用情况还分为单向不循环链表、单向循环链表两种。

(1)单向不循环链表

????????单向不循环链表是一种单向的链式结构,节点之间通过指针域互相关联,最后一个节点的指针域为空(NULL)。如下图所示:

???????

??下面用C语言实现一个单向不循环链表的代码。

1)先定义一个链表的节点。如下:

// 定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
	int  weight; // 苹果的重量
	int  hight;  // 苹果的高度
	// ... 		 // 还可以定义更多的其他的数据
}LinkData_t;

/*** 定义一个链表节点 ******/
typedef struct LinkNode_Struct
{
	LinkData_t data;				// 链表节点的数据域
	struct LinkNode_Struct *Next; 	// 链表节点的指针域
}LinkNode_t;

2)定义一个单向链表的头结点。如下:

/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点

3)初始化单向链表。如下:

// 初始化单向链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
	HeadNode->Next = NULL;
}

4)创建链表节点并接入到链表中。如下:

// 创建一个链表节点并接入到链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
	LinkNode_t *Node,*pf;
	LinkNode_t *xReturn = NULL;
	Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

	if (Node == NULL)
	{
		printf("节点创建失败!!!\r\n");
		return NULL;
	}

	pf = HeadNode;
	while(pf->Next != NULL)
	{
		pf = pf->Next;
	}
	pf->Next = Node;
	Node->Next = NULL;
	Node->data.hight = InsetData->hight;
	Node->data.weight = InsetData->weight;
	xReturn = Node;

	printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
	return xReturn;
}

5)删除链表中的节点。如下:

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
	int deleteFlag = 0;
	LinkNode_t *pf,*preStre;

	pf = preStre = HeadNode;

	do
	{
		if (pf->data.weight == weight){
			deleteFlag = 1;
			break;
		}
		preStre = pf;
		pf = pf->Next;
	}while (pf->Next != NULL);

	if (!deleteFlag)
	{
		printf("找不到这个节点!!!\r\n");
	}
	else
	{
		if(pf->Next == NULL)	// 该点是尾节点
		{
			preStre->Next = NULL;
		}
		else
		{
			preStre->Next = pf->Next;
		}
		free(pf);
		printf("节点weight = %d 销毁成功!\r\n",weight);
	}
}

6)输出整条链表的数据。如下:

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
	int length = 0;
	LinkNode_t *pf = HeadNode;

	if (pf->Next == NULL)
	{
		printf("该链表长度为零,不能输出结果!\r\n");
		return;
	}

	do	
	{
		pf = pf->Next;
		printf("weight = %d\r\n", (int)pf->data.weight);
		printf("height = %d\r\n", (int)pf->data.hight);
		printf("\r\n");
		length++;
	}while (pf->Next != NULL);
	printf("链表输出完成。长度为:%d\r\n",length);
}

7)按条件查询链表中某个节点的数据。如下:

// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
	int length = 0;
	char search_flag = 0;
	LinkNode_t *pf = HeadNode;

	if (pf->Next == NULL)
	{
		printf("该链表长度为零,不能输出结果!\r\n");
		return;
	}

	do	
	{
		pf = pf->Next;
		if(pf->data.weight == weight)
		{
			search_flag = 1;
			printf("weight = %d\r\n", (int)pf->data.weight);
			printf("height = %d\r\n", (int)pf->data.hight);
			printf("\r\n");
		}
		length++;
	}while (pf->Next != NULL);

	if(search_flag)
	{
		printf("链表查找结束。所在节点位置为:%d\r\n",length);
	}
	else
	{
		printf("整个链表中无满足此条件的节点!\r\n");
	}
}

? ? ? ?单向不循环链表的演示demo

????????注意:这个demo可以直接运行在控制台上输出显示!

void print_debug_info(void)
{
	printf("******** 链表控制台 *****************\r\n");
	printf("*                                  \r\n");
	printf("*  1:创建链表                      \r\n");
	printf("*  2:删除链表                      \r\n");
	printf("*  3:显示整条链表的数据             \r\n");
	printf("*  4:按条件查找链表节点             \r\n");
	printf("*  8:清空显示                      \r\n");
	printf("*  9:结束运行                      \r\n");
	printf("*                                  \r\n");
	printf("************************************\r\n");
}

int main(int argc, char *argv[]) 
{
	int Num,i,j;
	int Options;
	int weight,height;
	LinkData_t InsetData;

	Init_LinkNode(&AppleInfo_head);

	while (1)
	{
		print_debug_info();
		printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
		scanf("%d", &Options);
		switch (Options)
		{
			case 1:
				/*** 创建任意长度的链表 **********************************************************/
				printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
				scanf("%d", &Num);

				printf("请输入节点的数据:\r\n");
				for (i = 0; i < Num; i++)
				{
					printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
					scanf("%d %d", &weight,&height);
					InsetData.weight = weight;
					InsetData.hight  = height;
					printf("weight = %d height = %d\r\n",weight,height);

					if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
					{
						printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
					}
					else
					{
						printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
					}
				}
				printf("\r\n");
				break;
			
			case 2:
				/******* 删除链表中的某个节点 ***************************************************/
				printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
				scanf("%d", &Num);
				destroy_LinkNode(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 3:
				printf("链表数据为:\r\n");
				print_LinkNode_Info(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 4:
				printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
				scanf("%d", &Num);
				search_LinkNode_Info(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 8:
				system("cls");
				break;

			case 9:
				printf("退出链表控制台,请再次运行程序!\r\n");
				return;
				break;
			
			default:
				printf("无效的键值,请重新输入!\r\n");
				break;
		}
	}
	return 0;
}

(2)单向循环链表

????????单向循环链表是一种单向的可回头的链表,节点之间通过指针域互相关联,最后一个节点的指针域为头结点的地址。如下图所示:

?

下面用C语言实现一个单向循环链表的代码。

1)先定义一个链表的节点。如下:

// 定义一个链表节点的数据域。以记录一个苹果的信息为例,为方便说明,假设每个苹果的信息各不相同
typedef struct LinkData_struct
{
	int  weight; // 苹果的重量
	int  hight;  // 苹果的高度
	// ... 		 // 还可以定义更多的其他的数据
}LinkData_t;

/*** 定义一个链表节点 ******/
typedef struct LinkNode_Struct
{
	LinkData_t data;				// 链表节点的数据域
	struct LinkNode_Struct *Next; 	// 链表节点的指针域
}LinkNode_t;

2)定义一个单向链表的头结点。如下:

/*** 定义一个单向链表的头结点 ***/
LinkNode_t AppleInfo_head; //作为单向链表的一个头结点

3)初始化单向链表。如下:

// 初始化单向循环链表的头结点
void Init_LinkNode(LinkNode_t * HeadNode)
{
	HeadNode->Next = HeadNode;
}

4)创建链表节点并接入到链表中。如下:

// 创建一个链表节点并接入到单向循环链表中
LinkNode_t * LinkNode_Create(LinkNode_t * HeadNode, LinkData_t *InsetData)
{
	LinkNode_t *Node,*pf;
	LinkNode_t *xReturn = NULL;
	Node = (LinkNode_t *)malloc(sizeof(LinkNode_t));

	if (Node == NULL)
	{
		printf("节点创建失败!!!\r\n");
		return NULL;
	}

	pf = HeadNode;
	while(pf->Next != HeadNode)
	{
		pf = pf->Next;
	}
	pf->Next = Node;
	Node->Next = HeadNode;
	Node->data.hight = InsetData->hight;
	Node->data.weight = InsetData->weight;
	xReturn = Node;

	printf("完成一个链表节点的创建,地址 = 0x%X\r\n",xReturn);
	return xReturn;
}

5)删除链表中的节点。如下:

// 删除链表中的某个节点,根据weight进行删除
void destroy_LinkNode(LinkNode_t * HeadNode, int weight)
{
	int deleteFlag = 0;
	LinkNode_t *pf,*preStre;

	pf = preStre = HeadNode;

	do
	{
		preStre = pf;
		pf = pf->Next;
		if (pf->data.weight == weight){
			deleteFlag = 1;
			break;
		}
	}while (pf->Next != HeadNode);

	if (!deleteFlag)
	{
		printf("找不到这个节点!!!\r\n");
	}
	else
	{
		if(pf->Next == HeadNode)	// 该点是尾节点
		{
			preStre->Next = HeadNode;
		}
		else
		{
			preStre->Next = pf->Next;
		}
		free(pf);
		printf("节点weight = %d 销毁成功!\r\n",weight);
	}
}

6)输出整条链表的数据。如下:

// 输出显示整条链表
void print_LinkNode_Info(LinkNode_t * HeadNode)
{
	int length = 0;
	LinkNode_t *pf = HeadNode;

	if (pf->Next == HeadNode)
	{
		printf("该链表长度为零,不能输出结果!\r\n");
		return;
	}

	do	
	{
		pf = pf->Next;
		printf("weight = %d\r\n", (int)pf->data.weight);
		printf("height = %d\r\n", (int)pf->data.hight);
		printf("\r\n");
		length++;
	}while (pf->Next != HeadNode);
	printf("链表输出完成。长度为:%d\r\n",length);
}

7)按条件查询链表中某个节点的数据。如下:

// 按条件查询链表中某个节点的数据
void search_LinkNode_Info(LinkNode_t * HeadNode, int weight)
{
	int length = 0;
	char search_flag = 0;
	LinkNode_t *pf = HeadNode;

	if (pf->Next == HeadNode)
	{
		printf("该链表长度为零,不能输出结果!\r\n");
		return;
	}

	do	
	{
		pf = pf->Next;
		if(pf->data.weight == weight)
		{
			search_flag = 1;
			printf("weight = %d\r\n", (int)pf->data.weight);
			printf("height = %d\r\n", (int)pf->data.hight);
			printf("\r\n");
		}
		length++;
	}while (pf->Next != HeadNode);

	if(search_flag)
	{
		printf("链表查找结束。所在节点位置为:%d\r\n",length);
	}
	else
	{
		printf("整个链表中无满足此条件的节点!\r\n");
	}
}

单向循环链表的演示demo如下:

注意:这个demo可以直接运行在控制台上输出显示!

void print_debug_info(void)
{
	printf("******** 链表控制台 *****************\r\n");
	printf("*                                  \r\n");
	printf("*  1:创建链表                      \r\n");
	printf("*  2:删除链表                      \r\n");
	printf("*  3:显示整条链表的数据             \r\n");
	printf("*  4:按条件查找链表节点             \r\n");
	printf("*  8:清空显示                      \r\n");
	printf("*  9:结束运行                      \r\n");
	printf("*                                  \r\n");
	printf("************************************\r\n");
}

int main(int argc, char *argv[]) 
{
	int Num,i,j;
	int Options;
	int weight,height;
	LinkData_t InsetData;

	Init_LinkNode(&AppleInfo_head);

	while (1)
	{
		print_debug_info();
		printf("\r\n请输入需要操作的键值,按回车键确认!\r\n");
		scanf("%d", &Options);
		switch (Options)
		{
			case 1:
				/*** 创建任意长度的链表 **********************************************************/
				printf("请输入需要创建的链表节点的数量,按回车结束!\r\n");
				scanf("%d", &Num);

				printf("请输入节点的数据:\r\n");
				for (i = 0; i < Num; i++)
				{
					printf("请输入第 %d 节点的数据,weight = Height = ,输入完毕按回车结束!\r\n",i+1);
					scanf("%d %d", &weight,&height);
					InsetData.weight = weight;
					InsetData.hight  = height;
					printf("weight = %d height = %d\r\n",weight,height);

					if(LinkNode_Create(&AppleInfo_head, &InsetData) > NULL)
					{
						printf("节点 %d 创建成功!\r\n\r\n\r\n",i+1);
					}
					else
					{
						printf("节点 %d 创建失败!\r\n\r\n\r\n",i+1);
					}
				}
				printf("\r\n");
				break;
			
			case 2:
				/******* 删除链表中的某个节点 ***************************************************/
				printf("请输入需要删除的链表节点的weight,按回车结束!\r\n");
				scanf("%d", &Num);
				destroy_LinkNode(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 3:
				printf("链表数据为:\r\n");
				print_LinkNode_Info(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 4:
				printf("请输入需要查找的链表节点的weight,按回车结束!\r\n");
				scanf("%d", &Num);
				search_LinkNode_Info(&AppleInfo_head, Num);
				printf("\r\n");
				break;

			case 8:
				system("cls");
				break;

			case 9:
				printf("退出链表控制台,请再次运行程序!\r\n");
				return;
				break;
			
			default:
				printf("无效的键值,请重新输入!\r\n");
				break;
		}
	}
	return 0;
}


总结

? ? ? ? 单向不循环链表和单向循环链表基本是相同的,不同之处主要在于尾节点的指针域不同。单向不循环链表的尾节点的指针域为空,到尾节点的位置链表就结束了;单向循环链表的尾节点保存的是头节点的地址,从尾节点可以知道首节点的位置,形成一种循环的链式结构。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:12:58  更:2022-09-30 01:17:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:19:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码