当前位置: 首页 > article >正文

C语言之链表

1.知识百科

  链表(Linked List)是计算机科学中一种基础的数据结构,通过节点(Node)的链式连接来存储数据。每个节点包含两部分:存储数据的元素和指向下一个节点的指针(单链表)或前后两个指针(双链表)。以下是关键知识点:

  • 链表的核心特性
      动态内存分配:节点在内存中分散存储,通过指针逻辑连接,无需预先分配固定空间(与数组不同)。
      插入/删除高效:在已知位置插入或删除节点时,时间复杂度为 O(1)(但需先找到位置,查找时间为 O(n))。
      访问效率低:无法直接通过下标访问元素,需从头节点遍历,时间复杂度为 O(n)。

  • 链表的类型
      单链表:每个节点仅指向下一个节点;
      双链表:每个节点指向前一个和后一个节点,需频繁双向遍历(如文本编辑器)。
      循环链表 尾节点指向头节点,形成环;

  • 常见操作
      插入:在头部、尾部或指定位置插入节点。
      删除:删除指定节点(需处理指针指向)。
      遍历:从头节点依次访问每个节点。
      查找:按值或位置查找节点(需遍历)。

  • 链表 vs 数组
    在这里插入图片描述

2.C语言链表实现示例

  如下图所示,创建一个学生信息管理链表,数据域包含有姓名、学号id和成绩,指针域用于保存下一个节点的地址。
在这里插入图片描述

2.1创建链表节点

  1.定义结构体格式,保存学生信息。结果体中包含有指针域和数据域

typedef struct STU{
	/*数据域*/
	char name[50];
	char id[20];
	float score;
	/*指针域*/
	struct STU *next;//保存下一个成员的地址
}STU_INFO,*P_STU;

  2.创建链表节点,用于保存成员信息。采用尾插法添加。

/*添加节点:尾插法*/
STU_INFO *STU_AddNode(STU_INFO *head)
{
	STU_INFO *phead=head;
	if(phead==NULL)//链表头不存在
	{
		phead=malloc(sizeof(STU_INFO));//动态分配空间
		phead->next=NULL;//下一个成员指向NULL
		STU_Input(phead);
		return phead;//返回链表头
	}
	else //链表头存在
	{
		//1.偏移链表头,指向末尾位置
		while(phead->next!=NULL)
		{
			phead=phead->next;
		}
		//2.创建新的节点
		STU_INFO *new=malloc(sizeof(STU_INFO));
		//关联节点
		phead->next=new;
		new->next=NULL;
		phead=phead->next;
		//3.赋值
		STU_Input(new);
	}
	return head;//返回链表头
}

  3.为节点信息赋值。从键盘上录入学生信息数据。

/*赋值*/
void STU_Input(STU_INFO *node)
{
	if(node==NULL)return ;//地址为NULL
	printf("请输入姓名、学号、成绩:\n");
	scanf("%s%s%f",node->name,node->id,&node->score);
	while(getchar()!='\n');//清空缓冲区
}

2.2 链表节点遍历

  遍历链表节点,输出学生信息。

/*链表遍历*/
void STU_Output(STU_INFO *head)
{
	STU_INFO *phead=head;
	while(phead!=NULL)
	{
		printf("姓名:%s  学号:%s  成绩:%.1f\n",phead->name,phead->id,phead->score);
		phead=phead->next;
	}
}

2.3 链表测试

int main()
{
	/*1.创建链表头*/
	STU_INFO *head=NULL;
	int i=0;
	for(i=0;i<4;i++)
	{
		//创建链表头,添加节点
		head=STU_AddNode(head);
	}
	//链表遍历
	STU_Output(head);
}

  运行效果:

wbyq@wbyq-virtual-machine:$ ./a.out 
请输入姓名、学号、成绩:
小王 2025001 88
请输入姓名、学号、成绩:
小刘 2025002 99
请输入姓名、学号、成绩:
阿水 2025003 98
请输入姓名、学号、成绩:
小林 2025004 88
姓名:小王  学号:2025001  成绩:88.0
姓名:小刘  学号:2025002  成绩:99.0
姓名:阿水  学号:2025003  成绩:98.0
姓名:小林  学号:2025004  成绩:88.0

2.4 节点有序插入

  在一个有序的链表中,插入一个新的节点,保证链表依然有序。代码实现如下,以学号为例。

/*有序链表插入:按从小到大顺序
*/
P_STU STU_InserNodeOrder(P_STU head)
{ 
	if(!head){  //链表头位NULL
		head=malloc(sizeof(STU_INFO));
		head->next=NULL;
		STU_Input(head);
		return head;
	}
	//链表头不为NULL
	P_STU new=malloc(sizeof(STU_INFO));//添加新的节点
	STU_Input(new);//录入信息
	P_STU phead=head;
	P_STU temp=head;
	while(phead!=NULL)
	{
		if(strcmp(phead->id,new->id)>0)//条件成立,则将该节点插入到当前节点前面
		{
			if(phead==head)//当前插入的节点则作为整个链表的头节点
			{
				//节点插入代码
				/*
					插入新的数据: 小王 2 99  <----头
					链表头数据: 小李 5 88
					按从小到大顺序
				*/
				new->next=phead;
				head=new;
				return head;
			}
			else 
			{	
				/*
					链表头数据: 小王  5 88					
					节点1: 小李 8 99 
					插入的新节点:小陈 9 99  <----中间位置
					节点2 : 小刘 10 66
				*/
				temp->next=new;
				new->next=phead;
				return head;
			}
		}
		temp=phead;
		phead=phead->next;//偏移到下一个节点
	}
	/*
		情况3:
			链表头数据: 小王  5 88					
			节点1: 小李 8 99 
			节点2 : 小陈 10 66
			插入的新节点:小刘 11 66  <---尾插法
	*/
	temp->next=new;
	new->next=NULL;
	return head;
}

  有序插入测试示例:

int main()
{
	P_STU head=NULL;//定义一个结构体指针
	int i=0;
	//添加节点
	while(1)
	{
		head=STU_InserNodeOrder(head);
		STU_Output(head);
	}
	return 0;
}

  运行效果:

wbyq@wbyq-virtual-machine:/mnt/hgfs/ubuntu/c_progma$ ./a.out 
请输入姓名、学号、成绩:
小王 005 88
姓名:小王  学号:005  成绩:88.0
请输入姓名、学号、成绩:
小红 002 89
姓名:小红  学号:002  成绩:89.0
姓名:小王  学号:005  成绩:88.0
请输入姓名、学号、成绩:
小陈 003 99     
姓名:小红  学号:002  成绩:89.0
姓名:小陈  学号:003  成绩:99.0
姓名:小王  学号:005  成绩:88.0
请输入姓名、学号、成绩:
小林 001 100
姓名:小林  学号:001  成绩:100.0
姓名:小红  学号:002  成绩:89.0
姓名:小陈  学号:003  成绩:99.0
姓名:小王  学号:005  成绩:88.0
请输入姓名、学号、成绩:

2.5 清空链表

//清空链表
P_STU STU_NodeClear(P_STU head)
{
	
	if(head==NULL)return head;
	P_STU phead=head;
	P_STU temp;
	#if 0
	//链表头存在(从第一个子节点开始删除)
	while(phead->next!=NULL)
	{
		temp=phead->next;//保存当前要删除的地址
		printf("释放节点:%p\n",temp);
		phead->next=temp->next;
		free(temp);//释时节点
	}
	printf("释放链表头:%p\n",phead);
	//释放phead
	free(phead);
	return NULL;
	#endif
	
	//从链表头开始释放
	while(phead!=NULL)
	{
		temp=phead;//保存要删除的节点
		phead=phead->next;//保存下一个节点地址
		free(temp);
	}
	return NULL;
}

http://www.kler.cn/a/613533.html

相关文章:

  • 分布式光伏防逆流如何实现?
  • 每日免费分享之精品wordpress主题系列~DAY16
  • 云原生四重涅槃·破镜篇:混沌工程证道心,九阳真火锻金身
  • 可视化图解算法:递归基础
  • Pyside6介绍和开发第一个程序
  • GPT4o漫画制作(小白教程)
  • 后端开发中的文件上传的实现
  • Amazon CodeWhisperer 挑战十大排序算法
  • Vue下 Sortable 实现 table 列表字段可拖拽排序,显示隐藏组件开发
  • docker网桥问题导致ldap组件安装失败分析解决
  • 可直接套用的可视化模板
  • Python 3.13 正式支持 iOS:移动开发的新篇章
  • 深度学习|表示学习|多头注意力在计算时常见的张量维度变换总结|28
  • 大模型LLMs框架Langchain之工具Tools
  • C语言:第08天笔记
  • Selenium测试框架快速搭建
  • Go语言手动内存对齐的四大场景与实践指南
  • 语音机器人与智能体结合
  • 软考中级-软件设计师 23种设计模式(内含详细解析)
  • 软件性能测试中的“假阳性”陷阱