0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言_链表总结

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2022-08-14 09:53 次阅读

本篇文章介绍C语言链表相关知识点,涉及链表的创建、单向链表、循环链表、双向链表、单向循环链表,链表常见问题总结等,还列出了结构体数组与链表的练习题,将在下篇文章贴出完整代码。

1. 链表

1.1 结构体对比

数组特性: 内存空间连续、只能存放相同类型的数据
结构体特性: 内存空间连续、可以存放不同类型的数据

#include 
struct MyStruct
{
	int a;
	char b;
};

int main()
{
	struct MyStruct *p;
	struct MyStruct data={12,'A'};
	data.a=123;
	data.b='B';

	p=&data;
	printf("%d\n",p->a);
	printf("%c\n",p->b);
	return 0;
}

数组学生管理系统作业:

作业:   学生管理系统
需求:   (每一个功能都是使用函数进行封装)
1.实现从键盘上录入学生信息。 (姓名、性别、学号、成绩、电话号码)
2.将结构体里的学生信息全部打印出来。
3.实现根据学生的姓名或者学号查找学生,查找到之后打印出学生的具体信息。
4.根据学生的成绩对学生信息进行排序。
5.根据学号删除学生信息。

1.2 单向链表的创建与运用

链表: 单链表、双链表 区分: 循环和不循环链表
链表的特性: 一种数据结构的运行—>结构体。

学习结构体数组(编写学生管理系统): 学生的人数问题不好确定。
链表本身就是一个结构体。

单向链表的创建与运用:

#include 
#include 
#include 

//定义结构体
struct MyListStruct
{
	int a;
	struct MyListStruct *next; //结构体指针。存放下一个节点的地址
};

//定义链表头
struct MyListStruct *ListHead=NULL; 

//函数声明
struct MyListStruct *CreateListHead(struct MyListStruct *head);
void  PintListInfo(struct MyListStruct *head);
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode);
void DeleteListNode(struct MyListStruct *head,int a);
int main()
{
	int i;
	struct MyListStruct temp;
	int a;
	//1. 创建链表头
	ListHead=CreateListHead(ListHead);

	//2. 添加节点
	for(i=0; i<5; i++)
	{
		printf("输入新节点数据:");
		scanf("%d",&temp.a);
		AddListNode(ListHead,temp);
	}

	//3. 打印所有节点数据
	PintListInfo(ListHead);

	//4. 删除节点数据
	printf("输入删除的节点数据值:");
	scanf("%d",&a);
	DeleteListNode(ListHead,a);

	//5. 打印所有节点数据
	PintListInfo(ListHead);
	return 0;
}
/*
函数功能: 创建链表头
返回值  : 链表头指针
*/
struct MyListStruct *CreateListHead(struct MyListStruct *head)
{
	if(head==NULL)
	{
		head=malloc(sizeof(struct MyListStruct));
		head->next=NULL; 
	}
	return head; //返回链表头
}

/*
函数功能: 添加链表节点
说明: 链表头一般不存放数据
*/
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode)
{
	struct MyListStruct *p=head; //保存头地址
	struct MyListStruct *new_p=NULL;  //新的节点

	/*1. 寻找链表尾*/
	while(p->next!=NULL)
	{
		p=p->next; //移动到下一个地址
	}
    /*2. 创建新节点*/
	new_p=malloc(sizeof(struct MyListStruct));
	if(new_p==NULL)
	{
		printf("新节点内存申请失败!\n");
		return;
	}
	/*3. 新节点赋值*/
	memcpy(new_p,&NewNode,sizeof(struct MyListStruct)); //内存拷贝
	new_p->next=NULL; //尾节点指向空

	/*4. 新节点添加*/
	p->next=new_p;
}

/*
函数功能: 删除链表节点
*/
void DeleteListNode(struct MyListStruct *head,int a)
{
	struct MyListStruct *p=head; //保存头地址
	struct MyListStruct *tmp=NULL;
	/*查找数据存在的节点位置*/
	while(p->next!=NULL)
	{
		tmp=p; //保存上一个节点的地址
		p=p->next;
		if(p->a==a)  //查找成功
		{
			tmp->next=p->next; //将要删除节点的指针值赋值给删除节点的上一个节点指针域
			//tmp->next=tmp->next->next;
			free(p); //直接释放p节点空间
			//break;
			p=head; //重新指向链表头
		}
	}
}
/*
函数功能: 遍历所有链表信息
*/
void  PintListInfo(struct MyListStruct *head)
{
	int cnt=0;
	struct MyListStruct *p=head;
	printf("\n链表遍历的数据如下:\n");
	while(p->next!=NULL)
	{
		p=p->next;
		cnt++;
		printf("第%d个节点的数据=%d\n",cnt,p->a);
	}
}

作业:

1.看代码、理解链表的创建流程
2.编写出单向链表的基础运用
3.将之前的学生管理系统使用链表方式做出来

链表的功能:
(1)创建链表头
(2)在链表结尾添加一个节点
(3)删除指定的一个链表节点
(4)遍历链表,打印出所有的数据。
(5)在链表的指定节点的后面添加一个节点。
(6)根据链表节点里的数据对链表进行排序。
双向链表:
(1)使用逆向+顺向两种遍历方式删除链表节点,目的: 提高效率。
     类似于二分法查找。

2. 链表问题总结

动态空间分配:
#include 
#include 
#include 

int main()
{
	char *p=malloc(100); //申请动态空间。
	if(p==NULL)
	{
		return -1;
	}
	strcpy(p,"1234567890");
	printf("%s\n",p);
	return 0;
}

#include 
#include 
#include 

int main()
{
	char *p1=malloc(100); //申请动态空间。
	printf("%p\n",p1);
	char *p2=malloc(100); //申请动态空间。
	printf("%p\n",p2);
	char *p3=malloc(100); //申请动态空间。
	printf("%p\n",p3);
	char *p4=malloc(100); //申请动态空间。
	printf("%p\n",p4);
	return 0;
}
错误解决:
1.第一个错误开始解决
2.常规错误:  函数没有声明、分号每加、括号没有加、=
3.括号没有对齐。

3. 双向链表和循环链表

3.1 单向循环链表:

#include 
#include 
#include 

//定义结构体
struct MyListStruct
{
	int a;
	struct MyListStruct *next; //结构体指针。存放下一个节点的地址
};

//定义链表头
struct MyListStruct *ListHead=NULL;

//函数声明
struct MyListStruct *CreateListHead(struct MyListStruct *head);
void  PintListInfo(struct MyListStruct *head);
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode);
void DeleteListNode(struct MyListStruct *head,int a);
int main()
{
	int i;
	struct MyListStruct temp;
	int a;
	//1. 创建链表头
	ListHead=CreateListHead(ListHead);

	//2. 添加节点
	for(i=0; i<5; i++)
	{
		printf("输入新节点数据:");
		scanf("%d",&temp.a);
		AddListNode(ListHead,temp);
	}

	//3. 打印所有节点数据
	PintListInfo(ListHead);

	//4. 删除节点数据
	printf("输入删除的节点数据值:");
	scanf("%d",&a);
	DeleteListNode(ListHead,a);

	//5. 打印所有节点数据
	PintListInfo(ListHead);
	return 0;
}
/*
函数功能: 创建链表头
返回值  : 链表头指针
*/
struct MyListStruct *CreateListHead(struct MyListStruct *head)
{
	if(head==NULL)
	{
		head=malloc(sizeof(struct MyListStruct));
		head->next=head;
	}
	return head; //返回链表头
}

/*
函数功能: 添加链表节点
说明: 链表头一般不存放数据
*/
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode)
{
	struct MyListStruct *p=head; //保存头地址
	struct MyListStruct *new_p=NULL;  //新的节点
    
	/*1. 寻找链表尾*/
	while(p->next!=head)
	{
		p=p->next; //移动到下一个地址
	}
	/*2. 创建新节点*/
	new_p=malloc(sizeof(struct MyListStruct));
	if(new_p==NULL)
	{
		printf("新节点内存申请失败!\n");
		return;
	}
	/*3. 新节点赋值*/
	memcpy(new_p,&NewNode,sizeof(struct MyListStruct)); //内存拷贝
	new_p->next=head; //尾节点指向头

	/*4. 新节点添加*/
	p->next=new_p;
}

/*
函数功能: 删除链表节点
*/
void DeleteListNode(struct MyListStruct *head,int a)
{
	struct MyListStruct *p=head; //保存头地址
	struct MyListStruct *tmp=NULL;

	/*查找数据存在的节点位置*/
	while(p->next!=head)
	{
		tmp=p; //保存上一个节点的地址
		p=p->next;
		if(p->a==a)  //查找成功
		{
			tmp->next=p->next; //将要删除节点的指针值赋值给删除节点的上一个节点指针域
							   //tmp->next=tmp->next->next;
			free(p); //直接释放p节点空间
					 //break;
			p=head; //重新指向链表头
		}
	}
}
/*
函数功能: 遍历所有链表信息
*/
void  PintListInfo(struct MyListStruct *head)
{
	int cnt=0;
	struct MyListStruct *p=head;
	printf("\n链表遍历的数据如下:\n");
	while(p->next!=head)
	{
		p=p->next;
		cnt++;
		printf("第%d个节点的数据=%d\n",cnt,p->a);
	}
}

3.2 双向链表

#include 
#include 
#include 

//定义结构体
struct MyListStruct
{
	int a;
	struct MyListStruct *next; //结构体指针。存放下一个节点的地址
	struct MyListStruct *old;  //结构体指针。存放上一个节点的地址
};
//定义链表头
struct MyListStruct *ListHead=NULL;

//函数声明
struct MyListStruct *CreateListHead(struct MyListStruct *head);
void  PintListInfo(struct MyListStruct *head);
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode);
void DeleteListNode(struct MyListStruct *head,int a);
void  PintListInfo_old(struct MyListStruct *head);
int main()
{
	int i;
	struct MyListStruct temp;
	int a;
	//1. 创建链表头
	ListHead=CreateListHead(ListHead);

	//2. 添加节点
	for(i=0; i<5; i++)
	{
		printf("输入新节点数据:");
		scanf("%d",&temp.a);
		AddListNode(ListHead,temp);
	}

	//3. 打印所有节点数据
	PintListInfo(ListHead);
	PintListInfo_old(ListHead);

	//4. 删除节点数据
	printf("输入删除的节点数据值:");
	scanf("%d",&a);
	DeleteListNode(ListHead,a);

	//5. 打印所有节点数据
	PintListInfo(ListHead);
	PintListInfo_old(ListHead);
	return 0;
}
/*
函数功能: 创建链表头
返回值  : 链表头指针
*/
struct MyListStruct *CreateListHead(struct MyListStruct *head)
{
	if(head==NULL)
	{
		head=malloc(sizeof(struct MyListStruct));
		head->next=NULL; //尾节点指向空
		head->old=head;  //上一个节点指向头
	}
	return head; //返回链表头
}

/*
函数功能: 添加链表节点
说明: 链表头一般不存放数据
*/
void AddListNode(struct MyListStruct *head,struct MyListStruct NewNode)
{
	struct MyListStruct *p=head;     //保存头地址
	struct MyListStruct *new_p=NULL; //新的节点
    
	/*1. 寻找链表尾*/
	while(p->next!=NULL)
	{
		p=p->next; //移动到下一个地址
	}
	/*2. 创建新节点*/
	new_p=malloc(sizeof(struct MyListStruct));
	if(new_p==NULL)
	{
		printf("新节点内存申请失败!\n");
		return;
	}
	/*3. 新节点赋值*/
	memcpy(new_p,&NewNode,sizeof(struct MyListStruct)); //内存拷贝
	new_p->next=NULL; //尾节点指向NULL
	new_p->old=p;     //保存上一个节点的地址
	/*4. 新节点添加*/
	p->next=new_p;
}

/*
函数功能: 删除链表节点
顺向删除。
*/
void DeleteListNode(struct MyListStruct *head,int a)
{
	struct MyListStruct *p=head; //保存头地址
	struct MyListStruct *tmp=NULL;

	/*查找数据存在的节点位置*/
	while(p->next!=NULL)
	{
		tmp=p; //保存上一个节点的地址
		p=p->next;
		if(p->a==a)  //查找成功
		{
			tmp->next=p->next; //将要删除节点的指针值赋值给删除节点的上一个节点指针域
							   //tmp->next=tmp->next->next;
			p->next->old=tmp;  //保存上一个节点的地址

			free(p); //直接释放p节点空间
					 //break;
			p=head; //重新指向链表头
		}
	}
}
/*
函数功能: 遍历所有链表信息
从头到尾遍历
*/
void  PintListInfo(struct MyListStruct *head)
{
	int cnt=0;
	struct MyListStruct *p=head;
	printf("\n(顺向)链表遍历的数据如下:\n");
	while(p->next!=NULL)
	{
		p=p->next;
		cnt++;
		printf("第%d个节点的数据=%d\n",cnt,p->a);
	}
}

/*
函数功能: 遍历所有链表信息
从尾到头遍历
*/
void  PintListInfo_old(struct MyListStruct *head)
{
	int cnt=0;
	struct MyListStruct *p=head;
	printf("\n(逆向)链表遍历的数据如下:\n");
	/*1. 找到链表尾*/
	while(p->next!=NULL)
	{
		p=p->next;
	}
	/*2. 通过链表尾遍历链表的数据*/
	while(p!=head)
	{
		cnt++;
		printf("第%d个节点的数据=%d\n",cnt,p->a);
		p=p->old; //访问上一个节点
	}
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7527

    浏览量

    128196
  • 结构体
    +关注

    关注

    1

    文章

    125

    浏览量

    10749
  • 链表
    +关注

    关注

    0

    文章

    80

    浏览量

    10464
收藏 人收藏

    评论

    相关推荐

    源码|学生信息管理系统(C语言链表实现)

    源码|学生信息管理系统(C语言链表实现)
    发表于 11-03 10:24 393次阅读

    C语言算法题:反转一个单向链表

    链表是编程学习的一个难点。其实,在C语言编程以及单片机裸机开发中,链表运用并不多。但是如果想提升嵌入式技能水平或收入水平,可以考虑深入嵌入式系统层面(如参与操作系统设计、深入学习新的操作系统等),此时,
    发表于 06-21 11:07 387次阅读
    C<b class='flag-5'>语言</b>算法题:反转一个单向<b class='flag-5'>链表</b>

    C语言链表知识点(2)

    C语言链表知识点(2)
    发表于 08-22 10:38 177次阅读
    C<b class='flag-5'>语言</b><b class='flag-5'>链表</b>知识点(2)

    C语言单向链表

    本帖最后由 snowmay001 于 2016-5-22 15:57 编辑 lianbiao.cpp/* 练习使用链表:创建链表、遍历链表、查找节点、添加节点、删除节点*/#include
    发表于 05-22 15:53

    C语言链表的学习

    链表有有头链表和无头链表无头链表:所有的节点都包含了有效数据。有头链表:用一个固定的头节点来指代整个链表
    发表于 08-21 13:12

    C语言链表

    C语言链表,,,
    发表于 11-07 17:19

    C语言玩转链表

    C语言是必学的一个课程,不管你是单片机还是嵌入式物联网,都是基础,所以还是要好好学习的今天推荐的资料是关于C语言链表的资料我自己看了一下主要
    发表于 11-13 13:50

    玩转C语言链表-链表各类操作详解

      链表概述  链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。它可以根据需要开辟内存单元。链表有一个“头指针”变量,以head表示,它存放一个地址。该地址指向一个元素。链表
    发表于 09-18 13:30

    怎么实现c语言循环链表

    怎么实现c语言循环链表
    发表于 10-19 06:07

    C语言程序小知识点总结

    C语言总结(stm32嵌入式开发)文章目录C语言总结(stm32嵌入式开发)
    发表于 11-05 07:45

    如何在C语言中去创建一种双向链表

    双向链表的结构是由哪些部分组成的?如何在C语言中去创建一种双向链表呢?
    发表于 12-24 06:22

    请问链表在单片机C语言中有应用吗?

    链表在单片机C语言中有应用么?
    发表于 10-16 07:28

    C语言链表的作用是什么?

    C语言中指针用的很少,链表、文件操作几乎没用过,所以也不能理解到底有什么作用。各位有经常在做程序时会用到这些吗。
    发表于 11-06 06:23

    C语言实现单链表举例

    所谓链表,就是用一组任意的存储单元存储线性表元素的一种数据结构。链表又分为单链表、双向链表和循环链表等。我们先讲讲单
    发表于 07-11 16:40 87次下载
    C<b class='flag-5'>语言</b>实现单<b class='flag-5'>链表</b>举例

    C语言链表相关资料下载

    C语言链表相关资料
    发表于 03-08 10:47 5次下载