链表的排序、删除、修改、查找、创建,文件的导出、读取。

前言
初学C语言,请大佬多提宝贵意见,感激不尽。欢迎各位初学者前来交流。
/*

学生信息管理系统:
1.输入工程实验信息
2.显示所有信息
3.根据ID删除指定工程信息
4.根据名称查找工程信息
5.在序号前插入工程信息
6.根据ID插入工程信息
7.根据ID大小进行信息排序
8.根据ID修改信息
9.将信息导出
10.从文件中读取数据
11.删除链表


总结:
1.花了3个小时写完,与上次有进步。
2.不知道自己的 C 语言现在有没有入门,缺乏交流。
3.利用while,可以实现输入错误重新输入的目的。
4.凡是对结点中“数据域”中的“元素”进行修改的,都是用p=head.pNext,也就是p直接指向需要修改的那个结点,具体怎么理解,自己在思考。
5.凡是对链表中完整的结点做出修改的,如删除整个结点,添加结点等,只要打乱原有的排列顺序,都需要记住被修改结点的上一个结点,这样才能建立连续。
6.链表排序:
//选择排序的总体思想是:将已经挑选出来的结点进行删除,再对剩下的结点进行最大值或者最小值筛选。也就意味着,如果原来的链表还有用处,就需要重新创建一个链表,在这个链表上进行排序,再将筛选出的值赋值到第三个链表中。
//对链表进行选择排序法,至少需要两个链表。
7.删除链表。找到下一个结点,找到之后对当前的结点进行释放。


*/
————————————————
版权声明:本文为CSDN博主「sfdely」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sfdely/article/details/100558748

# include<stdio.h>
# include<stdlib.h>
# include<string.h>
# include<malloc.h>

struct Student 
{
	char ID[5];
	char name[20];
	int score;
	struct Student *pNext;
};
typedef struct Student STU;

STU head, *tail, *p;

void Input(void);
void Output(void);
void Delete(void);
void Search(void);
void Insert(void);
void Insert_ID(void);
void Sort_ID(void);
void Report(void);
void Putout(void);
void In_read(void);
void Delete_All(void);


int main(void)
{
	int n;
	while(1)
	{
		printf("1.输入工程实验信息\n");
		printf("2.显示所有信息\n");
		printf("3.根据ID删除指定工程信息\n");
		printf("4.根据名称查找工程信息\n");
		printf("5.在序号前插入工程信息\n");
		printf("6.根据ID插入工程信息\n");
		printf("7.根据ID大小进行信息排序\n");
		printf("8.根据ID修改信息\n");
		printf("9.将信息导出\n");
		printf("10.从文件中读取数据\n");
		printf("11.删除链表\n");
		printf("\n请输入需要的功能 :  ");
		scanf("%d", &n);

		switch(n)
		{
		case 1:Input(); break;
		case 2:Output(); break;
		case 3:Delete(); break;
		case 4:Search(); break;
		case 5:Insert(); break;
		case 6:Insert_ID(); break;
		case 7:Sort_ID(); break;
		case 8:Report(); break;
		case 9:Putout(); break;
		case 10:In_read(); break;
		case 11:Delete_All(); break;
		}
	}
	return 0;
}

void Input(void)
{
	int n, i;
	if(head.pNext != NULL)
	{
		printf("表格已存在,是否覆盖?否则按1");
		scanf("%d", &n);
		if(1 == n)		//等于判断,要将变量名放在后面,防止手误写成 n=1.
			return ;
	}
	
//链表创建
	printf("请输入有多少个学生: ");
	scanf("%d", &n);
	head.pNext  = NULL;
	tail = &head;
	for(i=0; i<n; i++)
	{
		p = (STU *)malloc(sizeof(STU));
		if(NULL == p)
		{
			printf("链表创建失败\n");
			return;
		}
		p->pNext = NULL;
		printf("请输入第%d个实验信息 : ", i+1);
		scanf("%s%s%d", p->ID, p->name, &p->score);
		tail->pNext = p;
		tail = p;
	}
	
	return ;
}

//链表输出
void Output(void)
{
	int i=1;

	p = head.pNext; //重点 !!凡是对结点中“数据域”中的“元素”进行修改的,都是用p=head.pNext,也就是p直接指向需要修改的那个结点,具体怎么理解,自己在思考。读取、输出、修改元素。
	if(NULL == head.pNext)
	{
		printf("表格不存在\n\n");
		return ;
	}
	while(p != NULL)	
	{

		printf("%-10d%-6s%-15s%-4d\n", i, p->ID, p->name, p->score);
		p = p->pNext;
		i++;
		
	}
	printf("\n\n");
	return ;
}

//删除结点
void Delete(void)
{
	STU *pr;
	char ch[20];
	int n = 3;

	if(NULL == head.pNext)
	{
		printf("表格不存在\n");
		return ;
	}
	
	while(3 == n)
	{
		p = &head;	//凡是对链表中完整的结点做出修改的,如删除整个结点,添加结点等,只要打乱原有的排列顺序,都需要记住被修改结点的上一个结点,这样才能建立连续。
		pr = p->pNext;
		
		printf("请输入需要删除的ID:");
		scanf("%s", ch);
		while(pr != NULL)
		{
			if(strcmp(ch, pr->ID) == 0)
			{
				p->pNext = pr->pNext;
				free(pr);
				return ;
			}
			p = p->pNext;
			pr = p->pNext;
			
		}
		printf("数据不存在,若要重新输入请按3,否则返回 :");
		scanf("%d", &n);			
	}

	return ;
}

//查找指定的结点中元素
void Search(void)
{
	char ch[20];
	int n=1, k=0;

	while(n)
	{
		p = head.pNext;	//p直接指向需要操作的结点即可。
		printf("请输入要查询的工程名\n");
		scanf("%s", ch);
		while(p!=NULL)
		{
			if(strcmp(ch, p->name) == 0)
			{
				printf("%-6s%-15s%-4d\n", p->ID, p->name, p->score);
				k++;
				printf("需要查询其他,请继续输入,返回请按0\n");
				scanf("%d", &n);
				if(0 == n)
					return ;
				else break;

			}
			p = p->pNext;
		}
		if(k == 0)
		{
			printf("输入的姓名有误,重新输入按1,返回上一层按其他: ");
			scanf("%d", &n);
			if(n != 1)
				return ;
		}
	}

	return ;
}

//插入结点
void Insert(void)
{
	int n, i=0;
	int k=1;
	STU *pr;

	printf("请输入需要在哪个序号前插入数据: ");
	scanf("%d", &n);

	while(n <= 0)
	{
		printf("请输入大于0的数 :");
		scanf("%d", &n);
	}
	while(k)
	{
		p = &head;	//p指向被操作的上一个结点,建立联系。
		i = 0;
		while(p->pNext != NULL)
		{
			i++;
			if(i == n)	//用i判断是第几个序列。
			{
				pr = (STU *)malloc(sizeof(STU));
				printf("请输入需要插入的数据: ");
				scanf("%s%s%d", pr->ID, pr->name, &pr->score);
				pr->pNext = p->pNext;
				p->pNext = pr;
				return ;
			}
			p = p->pNext;
		}
		printf("序号过大,请输入大于0,小于等于%d的数值范围 : " , i);
		
		while(n<=0 || n>i)
		{
			scanf("%d", &n);
		}
	}
	return ;
}

//根据元素内容 插入结点
void Insert_ID(void)
{
	char ch[20];
	STU *pr;
	p = &head;

	printf("请输入ID: ");
	scanf("%s", ch);
	while(p->pNext != NULL)
	{
		if(strcmp(p->pNext->ID, ch) == 0)
		{
			pr = (STU *)malloc(sizeof(STU));
			printf("请输入插入的工程名 :");
			scanf("%s%s%d", pr->ID, pr->name, &pr->score);
			pr->pNext = p->pNext;
			p->pNext = pr;
			return;
		}
		p = p->pNext;
			
	}
	printf("ID不存在\n");
	
	return ;
}

//根据元素进行链表排序。
//选择排序的总体思想是:将已经挑选出来的结点进行删除,再对剩下的结点进行最大值或者最小值筛选。也就意味着,如果原来的链表还有用处,就需要重新创建一个链表,在这个链表上进行排序,再将筛选出的值赋值到第三个链表中。
//对链表进行选择排序法,至少需要两个链表。
void Sort_ID(void)
{
	int i=1, j=1;
	STU *sort_p, *sort_tail, sort_head, *s_p, s_head, *s_tail;
//sort_为创建的第二个和原链表一模一样的链表
//s_为筛选完的链表。
	STU *pp, *pf;
	char ch[5];
	sort_tail = &sort_head;
	s_head.pNext = NULL;
	s_tail = &s_head;

//创建第二个链表,在第二个链表上进行处理,原来链表保存。
	p = head.pNext;
	while(p != NULL)
	{
		sort_p = (STU *)malloc(sizeof(STU));
		sort_p->pNext = NULL;
		strcpy(sort_p->name , p->name);
		strcpy(sort_p->ID , p->ID);
		sort_p->score = p->score;
		sort_tail->pNext = sort_p;
		sort_tail = sort_p;
		p = p->pNext;
	}

//下面这段是我用来判断第二个链表有没有赋值成功的,没有实际作用。
/*
	sort_p = sort_head.pNext;
	if(NULL == sort_head.pNext)
	{
		printf("表格不存在\n\n");
		return ;
	}
	while(sort_p != NULL)
	{

		printf("%-3d%-6s%-15s%-4d\n", i, sort_p->ID, sort_p->name, sort_p->score);
		sort_p = sort_p->pNext;
		i++;
	}
	printf("\n\n");
*/

//创建第三个链表(最终链表)
	s_head.pNext = NULL;
	while(1)
	{
/*
		if(head.pNext == NULL)
		{
			return;
		}
*/
		sort_p = &sort_head;
		strcpy(ch, sort_p->pNext->ID);	//ch存放的是需要进行筛选的最小值,读者若是不会,请自行查阅学习数组中的选择排序法。
		pp = NULL;		//指针pp用来记住存放最小值ID的“结点地址”。
		while(sort_p->pNext->pNext != NULL)
		{
			if(strcmp(ch, sort_p->pNext->pNext->ID) > 0)	//将存放的值和下一项进行比较,若是大于下一项,进行标记。
			{
				strcpy(ch , sort_p->pNext->pNext->ID);	//ch存最小的ID
				pp = sort_p->pNext;
			}
			sort_p = sort_p->pNext;
		}
	
	//注意!!链表的选择性排序法,要分清楚三种情况,读者自行理解。提示:首节点、尾结点、中间结点 中的地址域操作方式不同。
		if(pp == NULL)	//最小值在首节点
		{
//转移
			s_p = (STU *)malloc(sizeof(STU));
			s_p->pNext = NULL;
			strcpy(s_p->name, sort_head.pNext->name);
			strcpy(s_p->ID, sort_head.pNext->ID);
			s_p->score = sort_head.pNext->score;
			s_tail->pNext = s_p;
			s_tail = s_p;
//删除
			pf = sort_head.pNext;
			sort_head.pNext = pf->pNext;
			free(pf);	//重点!!!一定要对无用的malloc地址进行释放。后面如是。

		}
		else if(pp->pNext->pNext == NULL)		//最小值在尾结点。为什么这样写?读者自行体会。提示:需要对尾结点的上一个结点进行操作,所以需要对这个结点进行定位。
		{
			s_p = (STU *)malloc(sizeof(STU));
			s_p->pNext = NULL;
			strcpy(s_p->name, pp->pNext->name);
			strcpy(s_p->ID, pp->pNext->ID);
			s_p->score = pp->pNext->score;
			s_tail->pNext = s_p;
			s_tail = s_p;
			
			pf = pp->pNext;
			pp->pNext = NULL;
			free(pf);
		}
		else	//中间结点。
		{
			s_p = (STU *)malloc(sizeof(STU));
			s_p->pNext = NULL;
			strcpy(s_p->name, pp->pNext->name);
			strcpy(s_p->ID, pp->pNext->ID);
			s_p->score = pp->pNext->score;
			s_tail->pNext = s_p;
			s_tail = s_p;
			
			pf = pp->pNext;
			pp->pNext = pf->pNext;
			free(pf);
		}
		if (sort_head.pNext == NULL)
			break;
	}

//对排完序的第三个链表进行输出:
	s_p = s_head.pNext;
	if(NULL == s_head.pNext)
	{
		printf("表格不存在\n\n");
		return ;
	}
	while(s_p != NULL)
	{

		printf("%-10d%-6s%-15s%-4d\n", i, s_p->ID, s_p->name, s_p->score);
		s_p = s_p->pNext;
		i++;
	}
	printf("\n\n");

	return ;
}

//对链表中的元素进行修改
void Report(void)
{
	char ch[5];

	printf("请输入需要单独修改的ID :");
	scanf("%s", ch);

	p = head.pNext;
	while(p != NULL)
	{
		if(strcmp(p->ID, ch) == 0)
		{
			printf("请输入需要修改的内容: ");
			scanf("%s%d", p->name, &p->score);
		}
		p = p->pNext;
	
		
	}


	return ;
}


//对创建的链表进行输出文件。主要是为了方便后面的读取文件来创建表格,方便调试,不用在一个一个数据进行输入了。
void Putout(void)
{
	FILE *fp;
	int i = 1;

	fp = fopen("工程.txt", "a");
	if(NULL == fp)
	{
		printf("文件创建失败\n");
		return ;
	}

	p = head.pNext;
	while(p != NULL)
	{
		fprintf(fp, "%-3d%-6s%-15s%-4d\n", i, p->ID, p->name, p->score);
		p = p->pNext;
		i++;
	}

	fclose(fp);	//若是没有关闭文件,则文件不会创建,因为数据还在缓存区。
	printf("创建成功\n\n");
	return ;
}

//用文件来读取数据,不用再一个一个输入了,方便调试。
void In_read(void)
{
	int n, k, i, m=0;
	FILE *fp, *fp1;
	

	if(head.pNext != NULL)
	{
		printf("表格已存在,按1返回,否则重新覆盖:");
		scanf("%d", &n);
		if(n == 1)
			return ;
		Delete_All();	//删除已存在的表格。
	}

	tail = &head;
	fp = fopen("工程.txt", "r");
	fp1 = fopen("文本.txt", "w");

	if(NULL == fp)
	{
		printf("工程不存在\n");
		return ;
	}

	while(!feof(fp))
	{
		p = (STU*)malloc(sizeof(STU));
		p->pNext = NULL;

		if(k=fscanf(fp, "%d%s%s%d", &i, p->ID, p->name, &p->score) != 4 )	//此处见我另一个博客,有详细的解读。对fscanf/feof的理解。
		{
			free(p);	//正确写法
			break;
		}
		tail->pNext = p;
		tail = p;
	}
//	free(p);	原来是这样写的,这样写,如果文本中刚好文章结束,则把最后一个有效结点给删除了。
	p = &head;
	fclose(fp);
	fclose(fp1);
	return ;
}

//删除链表。找到下一个结点,找到之后对当前的结点进行释放。
void Delete_All(void)
{
	STU *pr;
	p = head.pNext;
	pr = p->pNext;
	while(pr != NULL)
	{
		free(p);
		p = pr;
		pr = p->pNext;
	}
	free(pr);
	head.pNext = NULL;
	printf("所有表格删除完成\n");


	return ;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值