#include <stdio.h>
#include <malloc.h>
#include <conio.h>
#include <string.h>
enum studentcategory { UNDERGRADUATE,POSTGRADUATE };
struct node * create_ _table(enum studentcategory category);
typedef struct node{
			int  id;						//学号:主键,唯一
			char name[10];					//姓名
			char sex[3];					//性别:男或女 
			char specialty[20];				//专业
			int classes;					//班级
			enum studentcategory category;	//枚举型学生类别;本科生、研究生
			int  math;						//高数
			int  english;					//英语
			int  clanguage;					//C语言
			int  comprehensive;				//课程综合
			int  thesis;					//毕业论文
			int  totalscore;				//总成绩
			int  classrank;					//班级排名
			int  schoolrank;				//校级排名
			struct node * next;
}Student;
//声明全局变量
Student * myHead=NULL;
int schoolCount[2];
char tmp;
FILE * fp=NULL;
char boy[]=\"男\";
char girl[]=\"女\";
//函数声明
void Input(void); 
void query_all();       //查询所有学生成绩信息
void inquire(void);     //查询界面
void insert_node0();    //获取用户要插入的学生成绩信息
void insert_node(Student *student);   //插入学生信息到链表中
void edit_node();       //修改学生成绩信息
Student * query_node(int cate,int id);  //根据学生种类和学生学号查询
void delete_node();     //删除链表中的节点
void updateRank();      //更新链表中所有学生的排名
void queryByClassAndCategory(); //根据班级和学生种类查询学生成绩信息
void queryFailByClassAndCategory(); //查询不及格的学生成绩信息
void queryByName();   //根据姓名查询学生成绩信息 
void count_analysis();    //统计模块
void queryById();     //根据ID查询学生成绩信息
FILE * openfile(char * openmode);
void saveData();      //将链表中的数据保存到本地
void initData();      //插入节点
int isCateAndIdViable(int cate,int id); //查询插入的学生学号和学生种类是否已经被保存 
Student * findPre(Student *student);    //查找某节点的前一个学生信息
void updateSchoolCount();   //更新学校排名
void release();    //退出系统的时候释放链表所占的内存空间
void stampscore();  //打印报表

//主函数
void main()
{
	char ch;
	initData();    //插入节点
	while(1)
	{
		system(\"cls\");//清屏

		//系统主页显示好看的布局
		printf(\"\\n\");
		printf(\"  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\");
		printf(\"\\n  *                                                                 *\");
		printf(\"\\n  *  		      学生成绩管理系统V1.0                          *\");
		printf(\"\\n  *                                                                 *\\n\");
		printf(\"  *			   【功能菜单】                             *\\n\");
		printf(\"  *           [1].录入信息              [2].修改信息                *\\n\");
		printf(\"  *                                                                 *\\n\");
		printf(\"  *           [3].删除信息              [4].查询成绩                *\\n\");
		printf(\"  *                                                                 *\\n\");
		printf(\"  *           [5].打印信息              [6].统计信息                *\\n\");
		printf(\"  *                                                                 *\\n\");
		printf(\"  *           [esc].退出                                            *\\n\");
		printf(\"  *                                                                 *\\n\");
		printf(\"  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\\n\");
		printf(\"  		    请输入操作编号(1~5):\");
sta:
		ch=getch();//获取用户输入的指令
		//判断用户输入的指令
		switch(ch)
		{
			case \'1\': insert_node0();    break;
			case \'2\': edit_node();       break;
			case \'3\': delete_node();     break;
			case \'4\': inquire();         break;
			case \'5\': stampscore();      break;
			case \'6\': count_analysis();	 break;
			case 27:
				//系统退出的时候,保存数据,释放链表的内存空间,然后清屏
				saveData();      //将链表中的数据保存到本地
				release();       //退出系统的时候释放链表所占的内存空间
				system(\"cls\");
				exit(0);
		}
	}
}

//插入节点
void initData(){
	long data_size=sizeof(Student);
	Student *p1=NULL;
	if((p1=(Student *)malloc(sizeof(Student)))==NULL){       
		printf(\"不能成功分配存储块\");
		exit(0);
	}
	fp=openfile(\"ab+\");
	fseek(fp,0L,SEEK_SET);
	fread(p1,data_size,1,fp);
	while(!feof(fp)){
	insert_node(p1);
	if((p1=(Student *)malloc(sizeof(Student)))==NULL){
		printf(\"不能成功分配存储块\");
		exit(0);
	}
	if(fread(p1,data_size,1,fp)==EOF){
		break;
	}
	}
	if(fclose(fp)){
		printf(\"未能正常关闭文件!\");
	}
}

//将链表中的数据保存到本地
void saveData(){
	Student * p1=myHead;
	Student data;
	if(myHead==NULL){
		return;
	}
	fp=openfile(\"wb\");
	rewind(fp);
	while(p1!=NULL){
		fwrite(p1,sizeof(Student),1,fp);  //将p1这个指针所指向的内容输出到fp这个文件中,每次输出的数据单元占sizeof(Student)个字节,总共输出1次
		p1=p1->next;
	}
	if(fclose(fp)){
		printf(\"未能正常关闭文件!\");
	}
}

//打开文件,返回文件指针
FILE *openfile(char * openmode){
	FILE *f1=NULL;
	if((f1=fopen(\"student.txt\",openmode))==NULL){
		printf(\"无法打开student.txt文件!\\n\");
		exit(0);
	}
	return(f1);
}

//统计模块
void count_analysis(){
	int res[6]={0,0,0,0,0,0};
	float ave=0.0;
	int count=0;
	int sum=0;
	int min=0;
	int max=0;
	Student * p1=myHead;
	int cate=-1;
	int score=0;
	int clazz=-1;
	int course=0;
	system(\"cls\");
	if(p1==NULL)
	{
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入类型(0:本科生,1:研究生):\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');//EOF是个宏,在stdil.h中定义,值为-1,也称结束标志
		while(cate<0||cate>1){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&cate);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');//当输入 ctrl+z 或 ctrl+c等组合键,getchar返回结束标志
		}
		printf(\"请输入班级:\");
		scanf(\"%d\",&clazz);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');//当程序从键盘获得了字符并且字符不是回车符的话,执行循环里的操作。

		while(clazz<=0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&clazz);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');//\\n回车(剔除了回车字符)
		}

		switch(cate){
			case UNDERGRADUATE:         //本科生
				printf(\"1.c语言 2.高数 3.英语\\n\");
				printf(\"请输入课程编号:\");
				scanf(\"%d\",&course);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				while(course>3||course<1){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&course);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}
			break;
			case POSTGRADUATE:         //研究生
				printf(\"1.课程综合 2.论文\\n\");
				printf(\"请输入编号:\");
				scanf(\"%d\",&course);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				while(course>2||course<1){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&course);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}
			break;
		}
		
		while(p1!=NULL){                 //循环,遍历链表里所有数据
			if((p1->category==cate)&&(p1->classes==clazz)){  
				switch(cate){
					case UNDERGRADUATE:                     //本科生
						switch(course){                     //课程
							case 1:
								score=p1->clanguage;
							break;
							case 2:
								score=p1->math;
							break;
							case 3:
								score=p1->english;
							break;
						}
					break;
					case POSTGRADUATE:                        //研究生
						switch(course){                       //课程
						case 1:
							score=p1->comprehensive;
						break;
						case 2:
							score=p1->thesis;
						break;
						}
					break;
				}
				if(score<=100&&score>=0){
					count++;
					sum+=score;                 //确定所要统计的班级的科目的总成绩
					if(count==1){
						max=score;
					}
					min=score;
					if(score<60){
						res[0]++;        //统计不及格人数
					}else{
						res[score/10-5]++;         //90~100为优;80~90为良;70~80为中;60~70为及格
					}
				}
			}
			p1=p1->next;            //跟踪链表增长
		}
			if(count!=0){
				ave=sum*1.0/count;
			}
			else{
				ave=0.0;	
			}
			printf(\"\\n-----------------------------------------\\n\");
			printf(\"平均分:%.2f\\t\\t\",ave);
			printf(\"最高分:%d\\n\",max);
			printf(\"最低分:%d\\n\",min);
			printf(\"优:%d人\\t\\t\",res[5]+res[4]);
			printf(\"良:%d人\\n\",res[3]);
			printf(\"中:%d人\\t\\t\",res[2]);
			printf(\"及格:%d人\\n\",res[1]);
			printf(\"不及格:%d人\\n\",res[0]);
			printf(\"\\n*****************************************\\n\");
			printf(\"超过平均分的学生名单:\\n\");
			printf(\"\\t姓名\\t\\t学号\\n\");
			p1=myHead;
			while(p1!=NULL){
			if(p1->category==cate&&p1->classes==clazz){
				switch(cate){
					case UNDERGRADUATE:
						switch(course){
						case 1:
							score=p1->clanguage;
						break;
						case 2:
							score=p1->math;
						break;
						case 3:
							score=p1->english;
						break;
						}
					break;
					case POSTGRADUATE:
						switch(course){
						case 1:
							score=p1->comprehensive;
						break;
						case 2:
							score=p1->thesis;
						break;
						}
					break;
				}
				if(score>=ave){
					printf(\"\\t%s\\t\\t%d\\n\",p1->name,p1->id);
				}	
			}
			p1=p1->next;
			}
					
		printf(\"\\n*****************************************\\n\");

			printf(\"不及格的学生名单:\\n\");          //打印不及格学生名单
			printf(\"\\t姓名\\t\\t学号\\n\");
			p1=myHead;
			while(p1!=NULL){
				if(p1->category==cate&&p1->classes==clazz){
					switch(cate){
						case UNDERGRADUATE:
							switch(course){
								case 1:
									score=p1->clanguage;
									break;
								case 2:
									score=p1->math;
									break;
								case 3:
									score=p1->english;
									break;
								}
							break;
						case POSTGRADUATE:
							switch(course){
								case 1:
									score=p1->comprehensive;
									break;
								case 2:
									score=p1->thesis;
									break;
							}
							break;
				}
				if(score<60&&score>=0){
					printf(\"\\t%s\\t\\t%d\\n\",p1->name,p1->id);
				}	
			}
			p1=p1->next;
		}
		printf(\"\\n*****************************************\\n\");
		printf(\"\\n查询结束,任意键继续...\");
		getch();
	}
}

//删除链表中的节点
void delete_node(){
	Student * p1=myHead,* p2=myHead;
	int cate=-1;
	int id=-1;
	system(\"cls\");
	if(myHead==NULL){
		printf(\"没有学生记录,无法进行删除操作!任意键继续...\\n\");
		getch();
		return;
	}
	printf(\"请输入类型(0:本科生,1:研究生):\");
	scanf(\"%d\",&cate);
	while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	while(cate<0||cate>1){
		printf(\"输入有误,请重新输入:\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	}
	printf(\"请输入学号:\");
	scanf(\"%d\",&id);
	while ((tmp = getchar()) != EOF && tmp != \'\\n\');

	while(id<0){
		printf(\"输入有误,请重新输入:\");
		scanf(\"%d\",&id);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	}

	while(((p1->category!=cate)||(p1->id!=id))&&(p1->next!=NULL)){
		p2=p1;
		p1=p1->next;   
	}
	if((p1->category==cate)&&(p1->id==id)){
		if(p1==myHead){
			myHead=p1->next;
		}else{
			p2->next=p1->next;
		}
		free(p1);//释放储存空间
		updateRank(); //更新链表中的排名
		printf(\"删除成功,任意键继续...\");
		getch();
	}else{
		printf(\"删除失败,任意键继续...\");
		getch();
	}
}

//查询界面
void inquire(void)
{
	char ch;
	while(1)
	{
		system(\"cls\");

				printf(\"\\n\");
		printf(\"  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\");
		printf(\"\\n  *                                                         *\");
		printf(\"\\n  *  		         查询学生成绩                       *\");
		printf(\"\\n  *                                                         *\\n\");
		printf(\"  *			 【功能菜单】                       *\\n\");
		printf(\"  *           [1].查询全部           [2].查询班级           *\\n\");
		printf(\"  *                                                         *\\n\");
		printf(\"  *           [3].姓名查询           [4].学号查询           *\\n\");
		printf(\"  *                                                         *\\n\");
		printf(\"  *           [5].查询不及格         [esc].返回首页         *\\n\");
		printf(\"  *                                                         *\\n\");
		printf(\"  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\\n\");
		printf(\"  		    请输入操作编号(1~5):\");

		ch=getch();

		switch(ch){
			case \'1\':
				query_all();
			break;
			case \'2\':
				queryByClassAndCategory();
			break;
			case \'3\':
				queryByName();
			break;
			case \'4\':
				queryById();
			break;
			case \'5\':
				queryFailByClassAndCategory();
			break;
			case 27:
			return;
		}
	}
}

//查询不及格的学生成绩信息
void queryFailByClassAndCategory(){
	Student * p1=myHead;
	int cate=-1;
	int score=0;
	int clazz=-1;
	int course=0;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入类型(0:本科生,1:研究生):\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		while(cate<0||cate>1){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&cate);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}
		printf(\"请输入班级:\");
		scanf(\"%d\",&clazz);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(clazz<=0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&clazz);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		switch(cate){
			case UNDERGRADUATE:                 //本科生
				printf(\"1.c语言 2.高数 3.英语\\n\");
				printf(\"请输入课程编号:\");
				scanf(\"%d\",&course);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				while(course<1||course>3){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&course);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
			}
			break;
			case POSTGRADUATE:                  //研究生
				printf(\"1.课程综合 2.论文\\n\");
				printf(\"请输入课程编号:\");
				scanf(\"%d\",&course);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				while(course<1||course>2){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&course);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}
			break;
		}
		while(p1!=NULL){
			if(p1->category==cate&&p1->classes==clazz){
				switch(cate){
					case UNDERGRADUATE:
						switch(course){
						case 1:
							score=p1->clanguage;
							break;
						case 2:
							score=p1->math;
							break;
						case 3:
							score=p1->english;
							break;
						}
					break;
					case POSTGRADUATE:
						switch(course){
						case 1:
							score=p1->comprehensive;
							break;
						case 2:
							score=p1->thesis;
							break;
						}
					break;
				}
				if(score<60&&score>=0){
					printf(\"****************************************\\n\");
					printf(\"学号:%d\\t\\t\",p1->id);
					printf(\"姓名:%s\\n\",p1->name);
					printf(\"性别:%s\\t\\t\",p1->sex);
					printf(\"班级:%d\\n\",p1->classes);
					printf(\"专业:%s\\n\",p1->specialty);
					switch(p1->category){
						case UNDERGRADUATE:
							printf(\"类型:本科生\\n\");
							printf(\"高数成绩:%d\\t\\t\",p1->math);
							printf(\"英语成绩:%d\\n\",p1->english);
							printf(\"c语言成绩:%d\\n\",p1->clanguage);
						break;
						case POSTGRADUATE :
							printf(\"类型:研究生\\n\");
							printf(\"课程论文成绩:%d\\t\\t\",p1->comprehensive);
							printf(\"毕业论文成绩:%d\\n\",p1->thesis);
						break;
					}
				printf(\"总成绩:%d\\n\",p1->totalscore);
				printf(\"班级排名:%d\\t\\t\",p1->classrank);
				printf(\"年级排名:%d\\n\",p1->schoolrank);
				printf(\"****************************************\\n\");
				}
				break;
			}
			p1=p1->next;
		}
		printf(\"****************************************\\n\");
		printf(\"查询结束,任意键继续...\");
		getch();
	}
}

//根据ID查询学生成绩信息
void queryById(){
	Student * p1=myHead;
	int id=-1;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入学号:\");
		scanf(\"%d\",&id);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		
		while(id<0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&id);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		printf(\"****************************************\\n\");
		while(p1!=NULL){
			if(id==p1->id){	
				printf(\"学号:%d\\t\\t\",p1->id);
				printf(\"姓名:%s\\n\",p1->name);
				printf(\"性别:%s\\t\\t\",p1->sex);
				printf(\"班级:%d\\n\",p1->classes);
				printf(\"专业:%s\\n\",p1->specialty);
				switch(p1->category){
					case UNDERGRADUATE:
					printf(\"类型:本科生\\n\");
					printf(\"高数成绩:%d\\t\\t\",p1->math);
					printf(\"英语成绩:%d\\n\",p1->english);
					printf(\"c语言成绩:%d\\n\",p1->clanguage);
					break;
					case POSTGRADUATE :
					printf(\"类型:研究生\\n\");
					printf(\"课程论文成绩:%d\\t\\t\",p1->comprehensive);
					printf(\"毕业论文成绩:%d\\n\",p1->thesis);
					break;
				}
				printf(\"总成绩:%d\\n\",p1->totalscore);
				printf(\"班级排名:%d\\t\\t\",p1->classrank);
				printf(\"年级排名:%d\\n\",p1->schoolrank);
				printf(\"****************************************\\n\");
				break;
			}
			p1=p1->next;
		}
		printf(\"查询结束,任意键继续...\");
		getch();
	}
}

//根据姓名查询学生成绩信息
void queryByName(){
	Student * p1=myHead;
	char name[10];
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入名字:\");
		gets(name);
		printf(\"****************************************\\n\");
		while(p1!=NULL){
			if(strcmp(name,p1->name)==0){
				printf(\"学号:%d\\t\\t\",p1->id);
				printf(\"姓名:%s\\n\",p1->name);
				printf(\"性别:%s\\t\\t\",p1->sex);
				printf(\"班级:%d\\n\",p1->classes);
				printf(\"专业:%s\\n\",p1->specialty);
				switch(p1->category){
					case UNDERGRADUATE:
					printf(\"类型:本科生\\n\");
					printf(\"高数成绩:%d\\t\\t\",p1->math);
					printf(\"英语成绩:%d\\n\",p1->english);
					printf(\"c语言成绩:%d\\n\",p1->clanguage);
					break;
					case POSTGRADUATE :
					printf(\"类型:研究生\\n\");
					printf(\"课程论文成绩:%d\\t\\t\",p1->comprehensive);
					printf(\"毕业论文成绩:%d\\n\",p1->thesis);
					break;
				}
				printf(\"总成绩:%d\\n\",p1->totalscore);
				printf(\"班级排名:%d\\t\\t\",p1->classrank);
				printf(\"年级排名:%d\\n\",p1->schoolrank);
				printf(\"****************************************\\n\");
			}
			p1=p1->next;
		}
	}
	printf(\"查询结束,任意键继续...\");
	getch();
}

//根据班级和学生种类查询学生成绩信息
void queryByClassAndCategory(){
	Student * p1=myHead;
	int cate=-1;
	int clazz=-1;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入类型(0:本科生,1:研究生):\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(cate<0||cate>1){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&cate);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}
		printf(\"请输入班级:\");
		scanf(\"%d\",&clazz);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		
		while(clazz<=0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&clazz);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		while(p1!=NULL){
			if(p1->category==cate&&p1->classes==clazz){
				printf(\"****************************************\\n\");
				printf(\"学号:%d\\t\\t\",p1->id);
				printf(\"姓名:%s\\n\",p1->name);
				printf(\"性别:%s\\t\\t\",p1->sex);
				printf(\"班级:%d\\n\",p1->classes);
				printf(\"专业:%s\\n\",p1->specialty);
				switch(p1->category){
					case UNDERGRADUATE:
					printf(\"类型:本科生\\n\");
					printf(\"高数成绩:%d\\t\\t\",p1->math);
					printf(\"英语成绩:%d\\n\",p1->english);
					printf(\"c语言成绩:%d\\n\",p1->clanguage);
					break;
					case POSTGRADUATE :
					printf(\"类型:研究生\\n\");
					printf(\"课程论文成绩:%d\\t\\t\",p1->comprehensive);
					printf(\"毕业论文成绩:%d\\n\",p1->thesis);
					break;
				}
				printf(\"总成绩:%d\\n\",p1->totalscore);
				printf(\"班级排名:%d\\t\\t\",p1->classrank);
				printf(\"年级排名:%d\\n\",p1->schoolrank);
			}
			p1=p1->next;
		}
		printf(\"****************************************\\n\");
		printf(\"查询结束,任意键继续...\");
		getch();
	}
}

//查询所有学生成绩信息
void query_all(){
	char c1;
	int count=0;
	int tmp=0;
	Student * p1=myHead;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		while(1){
		while(p1!=NULL){ 
			count++;
			printf(\"学号:%d\\t\\t\",p1->id);
			printf(\"姓名:%s\\n\",p1->name);
			printf(\"性别:%s\\t\\t\",p1->sex);
			printf(\"班级:%d\\n\",p1->classes);
			printf(\"专业:%s\\n\",p1->specialty);
			switch(p1->category){
				case UNDERGRADUATE:
					printf(\"类型:本科生\\n\");
					printf(\"高数成绩:%d\\t\\t\",p1->math);
					printf(\"英语成绩:%d\\n\",p1->english);
					printf(\"c语言成绩:%d\\n\",p1->clanguage);
				break;
				case POSTGRADUATE :
					printf(\"类型:研究生\\n\");
					printf(\"课程论文成绩:%d\\t\\t\",p1->comprehensive);
					printf(\"毕业论文成绩:%d\\n\",p1->thesis);
				break;
			}
			printf(\"总成绩:%d\\n\",p1->totalscore);
			printf(\"班级排名:%d\\t\\t\",p1->classrank);
			printf(\"年级排名:%d\\n\",p1->schoolrank);
			printf(\"****************************************\\n\");			
			p1=p1->next;
			if(count%10==0&&p1!=NULL){
				if(count==10){		
				    printf(\"[n]下一页 [e]尾页 [esc]退出\");
		getch4:		c1=getch();
					if(c1==27){
						return;
					}else if(c1==\'e\'){
						system(\"cls\");
						updateSchoolCount();             //更新学校排名
						tmp=(schoolCount[0]+schoolCount[1])/10*10;
						for(;count<tmp;count++){
							p1=p1->next;
						}
					}else if(c1==\'n\'){
						system(\"cls\");
					}
					else{
						goto getch4;
					}
				}else{
					printf(\"[f]首页 [l]上一页 [n]下一页 [e]尾页 [esc]退出\");
		getch3:		c1=getch();
					if(c1==27){
						return;
					}else if(c1==\'e\'){
						system(\"cls\");
						updateSchoolCount();
						tmp=(schoolCount[0]+schoolCount[1])/10*10;
						for(;count<tmp;count++){
							p1=p1->next;
						}
					}else if(c1==\'f\'){
						system(\"cls\");
						count=0;
						p1=myHead;
					}else if(c1==\'l\'){
						system(\"cls\");
						count=(count-1)/10*10-10;;
						p1=myHead;
						for(tmp=0;tmp<count;tmp++){
							p1=p1->next;
						}
					}else if(c1==\'n\'){
						system(\"cls\");
					}
					else{
						goto getch3;
					}
				}
			}
		}
		printf(\"没有更多的数据录了!\\n\");
		if(count>10){
			printf(\"[f]首页 [l]上一页 [esc]退出\");
getch2:		c1=getch();
			if(c1==\'f\'){
				system(\"cls\");
				count=0;
				p1=myHead;
			}else if(c1==\'l\'){
				system(\"cls\");
				count=(count-1)/10*10-10;;
				p1=myHead;
				for(tmp=0;tmp<count;tmp++){
					p1=p1->next;
				}
			}else if(c1==27){
				return;
			}
			else{
				goto getch2;
			}
		}else{
			printf(\"[esc]退出\");
getch1:		c1=getch();
			if(c1==27){
				return;
			}else {
				goto getch1;
			}
		}
		}
	}
}

//修改学生成绩信息
void edit_node(){
	Student * p1=myHead;
	Student * pre=NULL;
	int cate=-1;
	int id=-1;
	int sum=0;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生信息,无法修改...\\n\");
		getch();
		return;
	}
	printf(\"请输入类型(0:本科生,1:研究生):\");
	scanf(\"%d\",&cate);
	while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	while(cate>1||cate<0){
		printf(\"输入有误,请重新输入:\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	}
	printf(\"请输入学号:\");
	scanf(\"%d\",&id);
	while ((tmp = getchar()) != EOF && tmp != \'\\n\');

	while(id<0){
		printf(\"输入有误,请重新输入:\");
		scanf(\"%d\",&id);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	}

	p1=query_node(cate,id);//根据学生种类和学生学号查询
	if(p1==NULL){
		printf(\"无该学生记录!任意键继续...\\n\");
		getch();
	}
	else{

		printf(\"请输入该生的新数据\\n\");
		printf(\"姓名:\");
		scanf(\"%s\",&p1->name);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		printf(\"性别:\");
		scanf(\"%s\",p1->sex);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(strcmp(p1->sex,boy)!=0&&strcmp(p1->sex,girl)!=0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%s\",p1->sex);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}
		printf(\"班级:\");
		scanf(\"%d\",&p1->classes);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(p1->classes<=0){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&p1->classes);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		printf(\"专业:\");
		gets(p1->specialty);
		switch(p1->category){
			case UNDERGRADUATE:
				printf(\"高数成绩:\");
				scanf(\"%d\",&p1->math);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->math<-1||p1->math>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->math);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}
				if(p1->math!=-1)
					sum+=p1->math;
				printf(\"英语成绩:\");
				scanf(\"%d\",&p1->english);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->english<-1||p1->english>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->english);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}
				
				if(p1->english!=-1)
					sum+=p1->english;

				printf(\"c语言成绩:\");
				scanf(\"%d\",&p1->clanguage);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->clanguage<-1||p1->clanguage>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->clanguage);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->clanguage!=-1)
					sum+=p1->clanguage;

				break;
			case POSTGRADUATE :
				printf(\"课程论文成绩:\");
				scanf(\"%d\",&p1->comprehensive);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->comprehensive<-1||p1->comprehensive>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->comprehensive);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->comprehensive!=-1)
					sum+=p1->comprehensive;

				printf(\"毕业论文成绩:\");
				scanf(\"%d\",&p1->thesis);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->thesis<-1||p1->thesis>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->thesis);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->thesis!=-1)
					sum+=p1->thesis;

				break;
		}
		p1->totalscore=sum;
		
		pre=findPre(p1);//查找节点的前一个学生信息
		if(pre==NULL){
			myHead=p1->next;
		}else{
			pre->next=p1->next;
		}
		p1->next=NULL;
		insert_node(p1);//插入学生信息到链表中
		updateRank();//更新链表中学生排名
		printf(\"****************************************\\n\");
		printf(\"修改完成!任意键继续...\\n\");
		getch();
	}
}

//查找某节点的前一个学生信息
Student * findPre(Student *student){
	Student * p=myHead;
	Student * pre=NULL;
	if(p==NULL){
		return NULL;
	}
	if(student==NULL||student==p){
		return NULL;
	}
	while(p!=student){
		pre=p;
		p=p->next;
	}
	return pre;
}

//根据学生种类和学生学号查询
Student * query_node(int cate,int id){
	Student * p=myHead;
	if(p==NULL){
		return NULL;
	}
	while(((p->id!=id)||(p->category!=cate))&&(p->next!=NULL)) p=p->next;
	if((p->id!=id)||(p->category!=cate)) p=NULL;
	return p;
}

//插入学生信息到链表中
void insert_node(Student *student){
	Student *p0=NULL,*p1=NULL,*p2=NULL;
	p1=myHead;
	p0=student;
	if(myHead==NULL){
		myHead=p0;
		p0->next=NULL;
	}else{
		while((p0->totalscore<p1->totalscore)&&(p1->next!=NULL)){
			p2=p1;
			p1=p1->next;
		}
		if(p0->totalscore>=myHead->totalscore){
			p0->next=myHead;
			myHead=p0;
		}
		else if(p0->totalscore<p1->totalscore){
			p1->next=p0;
			p0->next=NULL;
		}
		else{
			p2->next=p0;
			p0->next=p1;
		}
	}
}

//更新链表中所有学生的排名
void updateRank(){
	int i=0;
	int j=0;
	int schoolRank[2];   //校级排名
	int schoolLastScore[2];   //最后一个人的成绩

	int classCount[2][100];   //总人数
	int classLastScore[2][100];   //最后成绩
	int classRank[2][100];    //班级排名
	int cate=-1;
	Student * p=myHead;
	//初始化数组
	for(i=0;i<2;i++){
		for(j=0;j<100;j++){
			classLastScore[i][j]=-1;
			classRank[i][j]=0;
			classCount[i][j]=0;
		}
	}
	schoolRank[0]=0;
	schoolRank[1]=0;
	schoolCount[0]=0;      //两种学生类型总人数
	schoolCount[1]=0;
	schoolLastScore[0]=-1;
	schoolLastScore[1]=-1;

	if(myHead==NULL){
		return;
	}
	while(p!=NULL){
		cate=p->category;  
		classCount[cate][(p->classes)]++; 
		schoolCount[cate]++;
		if(schoolLastScore[cate]!=p->totalscore){   
			schoolLastScore[cate]=p->totalscore;
			schoolRank[cate]=schoolCount[cate];
		}
		p->schoolrank=schoolRank[cate];     //校级排名

		if(classLastScore[cate][(p->classes)]!=p->totalscore){
			classLastScore[cate][(p->classes)]=p->totalscore;
			classRank[cate][(p->classes)]=classCount[cate][(p->classes)];
		}
		p->classrank=classRank[cate][(p->classes)];    //班级排名
		p=p->next;
	}
}


//获取用户要插入的学生成绩信息
void insert_node0(){
	int i=0;
	int num=0;
	int cate=-1;
	int totalscore=0;
	Student *p1=NULL;
	system(\"cls\");                   
	printf(\"请输入录入数量:\");
	scanf(\"%d\",&num);
	while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	
	while(num<0)
	{
		printf(\"输入有误,请重新输入:\");
		scanf(\"%d\",&num);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
	}

	for(i=1;i<=num;i++)
	{
		totalscore=0;
		if((p1=(Student *)malloc(sizeof(Student)))==NULL) //新节点
		{
			printf(\"不能成功分配存储块\");
			exit(0);
		}
		//p1->next=NULL;  //新节点指向空
repeinsert:	
		printf(\"请输入第%d个学生的学号:\",i);
		scanf(\"%d\",&p1->id);   //新节点指向id
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(p1->id<0)
		{
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&p1->id);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		printf(\"请输入第%d个学生的类型(0:本科生,1:研究生):\",i);
		scanf(\"%d\",&p1->category);      //新节点指向category
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		while(p1->category<0||p1->category>1)
		{
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&p1->category);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}
		
		if(!isCateAndIdViable(p1->category,p1->id)){       //查询插入的学生学号和学生种类是否已经被保存,函数返回为0,已存在
			printf(\"所输入类型的学号已经存在,请重新输入,任意键继续...\\n\");
			getch();
			system(\"cls\");
			goto repeinsert;
		}
		printf(\"请输入第%d个学生的姓名:\",i);
		scanf(\"%s\",&p1->name);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		printf(\"请输入第%d个学生的性别(男、女):\",i);
		scanf(\"%s\",p1->sex);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(strcmp(p1->sex,boy)!=0 && strcmp(p1->sex,girl)!=0)      //对两个字符串自左至右逐个字符相比(按ASCII码值大小比较),=时返回0
		{
			printf(\"输入有误,请重新输入:\");
			scanf(\"%s\",p1->sex);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		printf(\"请输入第%d个学生的班级:\",i);
		scanf(\"%d\",&p1->classes);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');

		while(p1->classes<=0)
		{
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&p1->classes);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}

		printf(\"请输入第%d个学生的专业:\",i);
		gets(p1->specialty);
		switch(p1->category){
			case UNDERGRADUATE:        //本科生
				printf(\"请输入第%d个学生的高数成绩:\",i);
				scanf(\"%d\",&p1->math);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->math<-1||p1->math>100)
				{
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->math);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->math!=-1) totalscore+=p1->math;          //总成绩里加高数成绩
				
				printf(\"请输入第%d个学生的英语成绩:\",i);
				scanf(\"%d\",&p1->english);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->english<-1||p1->english>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->english);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->english!=-1) totalscore+=p1->english;      //总成绩里加英语成绩
				
				printf(\"请输入第%d个学生的c语言成绩:\",i);
				scanf(\"%d\",&p1->clanguage);	
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->clanguage<-1||p1->clanguage>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->clanguage);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->clanguage!=-1) totalscore+=p1->clanguage;      //总成绩里加c语言成绩
			break;
			case POSTGRADUATE :            //研究生
				printf(\"请输入第%d个学生的课程论文成绩:\",i);
				scanf(\"%d\",&p1->comprehensive);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->comprehensive<-1||p1->comprehensive>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->comprehensive);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->comprehensive!=-1) totalscore+=p1->comprehensive;
				printf(\"请输入第%d个学生的毕业论文成绩:\",i);
				scanf(\"%d\",&p1->thesis);
				while ((tmp = getchar()) != EOF && tmp != \'\\n\');

				while(p1->thesis<-1||p1->thesis>100){
					printf(\"输入有误,请重新输入:\");
					scanf(\"%d\",&p1->thesis);
					while ((tmp = getchar()) != EOF && tmp != \'\\n\');
				}

				if(p1->thesis!=-1) totalscore+=p1->thesis;
				break;
		}
		p1->totalscore=totalscore;
		insert_node(p1);       //插入学生信息到链表中
		updateRank();          //更新链表中学生的排名
		printf(\"****************************************\\n\");
	}
	printf(\"录入成功,任意键继续...\");
	getch();
	return;
}

//查询插入的学生学号和学生种类是否已经被保存
int isCateAndIdViable(int cate,int id)
{
	Student *p1=myHead;
	if(p1==NULL) return 1;
	while(p1!=NULL){
		if(p1->category==cate&&p1->id==id){
			return 0;
		}
		p1=p1->next;        //跟踪链表增长
	}
	return 1;
}

//更新学校排名
void updateSchoolCount()
{
	Student * student=myHead;
	if(myHead==NULL){
		schoolCount[0]=0;
		schoolCount[1]=0;
		return;
	}
	schoolCount[0]=0;
	schoolCount[1]=0;
	while(student!=NULL){
		schoolCount[student->category]++;
		student=student->next;
	}
}

//退出系统的时候释放链表所占的内存空间
void release(){
	Student * p=myHead;
	Student * p1=NULL;
	while(p!=NULL){
		p1=p->next;
		free(p);
		p=p1;
	}
	myHead=NULL;
}

//打印报表
void stampscore(){
	Student * p1=myHead;
	int cate=-1;
	system(\"cls\");
	if(p1==NULL){
		printf(\"没有学生记录,任意键继续...\\n\");
		getch();
		return;
	}else{
		printf(\"请输入类型(0:本科生,1:研究生):\");
		scanf(\"%d\",&cate);
		while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		while(cate<0||cate>1){
			printf(\"输入有误,请重新输入:\");
			scanf(\"%d\",&cate);
			while ((tmp = getchar()) != EOF && tmp != \'\\n\');
		}
		system(\"cls\");
		if (cate==0){
			printf(\"*******************************本科生成绩报表**********************************\\n\");
			printf(\"学号\\t姓名\\t性别\\t班级\\t专业\\t高数\\t英语\\tc语言\\t总成绩\\t校级排名\\n\");
		}
		else{
			printf(\"*******************************研究生成绩报表**********************************\");
			printf(\"学号\\t姓名\\t性别\\t班级\\t专业\\t课程论文  毕业论文  总成绩  校级排名\\n\");
		}
		while(p1!=NULL){
			if(p1->category==cate){
				switch(cate){
					case UNDERGRADUATE:
					printf(\"%d\\t%s\\t%s\\t%d\\t%s\\t%d\\t%d\\t%d\\t%d\\t%d\\n\",
						p1->id,p1->name,p1->sex,p1->classes,p1->specialty,p1->math,p1->english,p1->clanguage,p1->totalscore,p1->schoolrank);
					break;
					case POSTGRADUATE :
					printf(\"%d\\t%s\\t%s\\t%d\\t%s\\t%d\\t%5d\\t%8d\\t%d\\n\",
						p1->id,p1->name,p1->sex,p1->classes,p1->specialty,p1->comprehensive,p1->thesis,p1->totalscore,p1->schoolrank);
					break;
				}
			}
			p1=p1->next;
		}
		printf(\"*******************************************************************************\\n\");
	}
	printf(\"查询结束,任意键继续...\");
	getch();
}
收藏 打印