【C语言】一个学生信息排序程序(学生信息表)【注释详细】【链表】

题目

一、编写一个学生信息排序程序。要求:

1、可随时输入n个学生的信息和成绩(n不设置上限)。

2、学生信息包括:学号、姓名、性别、专业、学院;三门课程成绩。

3、为用户提供一个排序选择列表,使得用户能够按照上述所列信息(学号、姓名、性别、专业、学院、自定义的三门课程)中的至少一个字段进行排序,并显示其结果。

解题思路

本题因为n不设置上限,数据量过大就无法使用数组了,所以下面提供一种链表的思路。首先定义一个结构体用于存放单个学生的数据,结构体中定义一个结构体变量指针指向下一个学生,构成链表,每一次新加入一个学生就为其分配一块内存空间,并加入到链表串中。

完整代码

#include<stdio.h>
#include <stdlib.h> 
#include<string.h>
typedef struct student//定义一个链表数据类型,不用每次都写struct了
{
	char* number;//学号
	char* name;//姓名
	char* sex;  //性别
	char* major;//专业
	char* college;//学院
	int score1;//高数成绩
	int score2;//英语成绩
	int score3;//c语言成绩
	struct student* next;//链表的下一个元素
}student;
void sortmenu();//打印排序选择菜单
void menu();//打印选择菜单
void add(student* p);//增加一个学生
void print(student* p);//打印数据表
student* findend(student* head);//返回新链表的结尾元素
student* sort(int number, student* head, int(*com) (student* p));//排序函数
int compare_number(student* p);//比较相邻两个链表元素的学号
int compare_name(student* p);//比较相邻两个链表元素的姓名
int compare_sex(student* p);//比较相邻两个链表元素的性别
int compare_major(student* p);//比较相邻两个链表元素的专业
int compare_college(student* p);//比较相邻两个链表元素的学院
int compare_score1(student* p);//比较相邻两个链表元素的高数成绩
int compare_score2(student* p);//比较相邻两个链表元素的英语成绩
int compare_score3(student* p);//比较相邻两个链表元素的c语言成绩
void clearlist(student* head);//删除数据表
int main()
{
	int choose = 0, sortchoose = 0,number = 0;//choose选择的序号 sortchoose选择的排序序号 number统计现有学生人数
	student* now, * pre;//*now当前链表元素的指针 *pre前一个链表元素的指针
	student* head = NULL;//链表头
	do
	{
		menu();//打印选择菜单
		scanf("%d", &choose);//读入选项
		switch (choose)
		{
			case 1://增加一个学生
				now = (student*)malloc(sizeof(student));//为当前链表元素分配地址
				if (head == NULL)head = now ;//如果链表头为空,则当前链表元素为链表头
				else pre->next = now;//把上个链表元素的next指向现在的链表元素的地址,即把当前元素接入链表
				now->next = NULL;//当前元素的下一个元素定为空
				add(now);//增加一个元素
				pre = now;//为下一个元素增加做准备
			    number++;//链表元素增加,学生人数增加
				break;
			case 2://排序
				sortmenu();//打印排序选择菜单
				scanf("%d", &sortchoose);//读入选项
				switch (sortchoose)
				{
				case 1:
					head = sort(number, head, compare_number);//按学号排序并读入新链表的链表头
					pre = findend(head);//读入新链表的链表尾
					printf("\n按学号排序:\n");
					print(head);//打印信息表
					break;
				case 2:
					head = sort(number, head, compare_name);
					pre = findend(head);
					printf("\n按姓名排序:\n");
					print(head);
					break;
				case 3:
					head = sort(number, head, compare_sex);
					pre = findend(head);
					printf("\n按性别排序:\n");
					print(head);
					break;
				case 4:
					head = sort(number, head, compare_major);
					pre = findend(head);
					printf("\n按专业排序:\n");
					print(head);
					break;
				case 5:
					head = sort(number, head, compare_college);
					pre = findend(head);
					printf("\n按学院排序:\n");
					print(head);
					break;
				case 6:
					head=sort(number, head, compare_score1);
					pre = findend(head);
					printf("\n按高数成绩排序:\n");
					print(head);
					break;
				case 7:
					head = sort(number, head, compare_score2);
					pre = findend(head);
					printf("\n按英语成绩排序:\n");
					print(head);
					break;
				case 8:
					head = sort(number, head, compare_score3);
					pre = findend(head);
					printf("\n按c语言成绩排序:\n");
					print(head);
					break;
				default:printf("请重新选择\n\n");
				}
				break;
			case 3:
				print(head);//打印信息表
				break;
			case 0: break;
			default:printf("请重新选择\n\n"); break;
		}
	} while (choose);//当chose为真不为零(退出为零)
	printf("\n正在删除数据表...\n");
	clearlist(head);//删除数据表
	printf("删除成功\n");//面子工程,像模像样,嘿嘿
	printf("已退出程序\n");
	return 0;
}
void menu()//打印选择菜单
{
	printf("请选择序号:\n");
	printf("1:增加一个学生\n");
	printf("2:排序\n");
	printf("3:打印数据表\n");
	printf("0:退出\n");
	printf("在此输入:");
}
void sortmenu()//打印排序选择菜单
{
	printf("请选择排序方式:\n");
	printf("1:学号 ");
	printf("2:姓名 ");
	printf("3:性别 ");
	printf("4:专业 ");
	printf("5:学院\n");
	printf("6:高数成绩 ");
	printf("7:英语成绩 ");
	printf("8:c语言成绩\n");
	printf("在此输入:");
}
void add(student* p)//增加一个学生
{
	p->number = (char*)malloc(100);//为新学生的学号分配内存
	p->sex = (char*)malloc(10);
	p->name = (char*)malloc(100);
	p->major = (char*)malloc(100);
	p->college = (char*)malloc(100);
	printf("请输入学号:\n");
	scanf("%s", p->number);//读入学号
	printf("请输入姓名:\n");
	scanf("%s", p->name);
	printf("请输入性别(nan或nv):\n");
	scanf("%s", p->sex);
	printf("请输入专业:\n");
	scanf("%s", p->major);
	printf("请输入学院:\n");
	scanf("%s", p->college);
	printf("请输入高数成绩:\n");
	scanf("%d", &p->score1);
	printf("请输入英语成绩:\n");
	scanf("%d", &p->score2);
	printf("请输入c语言成绩:\n");
	scanf("%d", &p->score3);
}
student* findend(student* head)//返回新链表的结尾元素
{
	student* p = head;
	while (p!=NULL&&p->next!= NULL)//寻找新链表的结尾元素
	{
		p = p->next;
	}
	return p;//返回新链表的结尾元素
}
void print(student* head)//打印数据表
{
	student* p = head;
	int count = 1;//排名序号
	printf("序号\t学号\t姓名\t性别\t专业\t学院\t高数\t英语\tc语言\n");
	while (p != NULL)
	{
		printf("%d\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%d\n",count,p->number,p->name,p->sex,p->major,p->college,p->score1,p->score2,p->score3);
		p = p->next;//下一个学生
		count++;//序号加1
	}
	printf("\n");
}
student* sort(int number, student* head,int(* compare) (student* p))//按某关键字排序 本程序最难的代码 
//number 学生人数 * head链表头 int(* compare) (student* p) 排序的关键字,函数指针,指向比较两个相邻学生的函数
{
	student* p, * q, * temp;
	//* p是前面的指针(探路比较大小用) * q是后面的指针(存储p的前一个元素,链表元素交换用)* temp 中间商指针,交换元素用
	int i, j;//冒泡排序的两次循环参数
	for (i = 0; i < number - 1; i++)//冒泡排序的趟数
	{
		p = head;//p,q归位,指向链表头
		q = head;
		for (j = 0; j < number - 1 - i ; j++)//冒泡排序一趟的比较
		{   
			if (compare(p)<0)//调用compare指向的比较函数
			{
				//如果现在的元素的某项数据小于下一个元素的某项数据,则两个链表元素交换位置
				//以下代码比较玄学,不容易讲清楚,建议自己手动代入数据或通过调试一步一步研究
				//本人小菜鸡一枚,水平有限,代码太复杂,希望大佬能简化下面的代码,把两种情况统一
				if (p == head)//如果现在的元素是链表头
				{
					head = p->next;//新链表头变为现在的元素的下一个元素
					q->next = p->next;
					temp = p->next->next;//中间变量暂存
					p->next->next = p;
					p->next = temp;
					p = head;
					q = head;
				}
				else
				{
				q->next = p->next;
				temp = p->next->next;
				p->next->next = p;
				p->next = temp;
				p = q->next;
				}
			}
			q = p;
			p = p->next;//p指向下一个元素
		}
	}
	return head;
}
int compare_number(student* p)//比较相邻两个链表元素的学号,为了字母升序排列所以strcmp前面加符号
{
	return -strcmp(p->number, p->next->number);
}
int compare_name(student* p)//比较相邻两个链表元素的姓名
{
	return -strcmp(p->name, p->next->name);
}
int compare_sex(student* p)//比较相邻两个链表元素的性别
{
	return -strcmp(p->sex, p->next->sex);
}
int compare_major(student* p)//比较相邻两个链表元素的专业
{
	return -strcmp(p->major, p->next->major);
}
int compare_college(student* p)//比较相邻两个链表元素的学院
{
	return -strcmp(p->college, p->next->college);
}
int compare_score1(student* p)//比较相邻两个链表元素的高数成绩
{
	return (p->score1) - (p->next->score1);
}
int compare_score2(student* p)//比较相邻两个链表元素的英语成绩
{
	return (p->score2) - (p->next->score2);
}
int compare_score3(student* p)//比较相邻两个链表元素的c语言成绩
{
	return (p->score3) - (p->next->score3);
}
void clearlist(student* head)//删除数据表
{
	student* p, * q;//* p当前要删除的链表元素  * q暂存p的下一个元素  
	p = head;//从链表头开始删除
	while (p != NULL)
	{
		q = p->next;//暂存p的下一个元素
		free(p);//释放内存
		p = q;//p指向下一个元素
	}
}

运行截图

 //qq长截图长度受限了,再补一张

//非法输入或未输入信息  

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值