题目
一、编写一个学生信息排序程序。要求:
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长截图长度受限了,再补一张
//非法输入或未输入信息