#include <stdio.h>
#include <string.h>
#include <iostream.h>
#include <stdlib.h>
#include <windows.h>
typedef struct studentinfo //结构体定义
{
int num//学号
char name[64]//姓名
int sex//性别,1为男性,0为女性
float math//数学
float english//英语
float politic//政治
float chinese//语文
float total//总成绩
struct studentinfo *next
}STUDENT
#define FILENAME "D:\\1.txt"
//定义默认的数据库文件
#define DELAYTIME 1500
//显示信息,延时
void create_menu()
STUDENT * new_student()
STUDENT* create_linkbyfile(char *)
STUDENT *del_info(STUDENT *)
int save_info(char *,STUDENT *,int)
int find_infile_printf(char *)
int pri_whole_link(STUDENT *)
STUDENT* printf_sort(STUDENT *)
void free_link(STUDENT *)
void main() //主函数
{
create_menu()
}
STUDENT * reverse(STUDENT *head)
//功能:链表反转顺序
//参数:head链表头结点指针
{
STUDENT *ptemp,*p1
if(head==NULL)
{
return 0
}
p1=head//p1使之永远指向排好序的第一个结点,初值为head,head使之永远是已经排好序的最后一个结点
while(head->next!=NULL)//本次循环使ptemp排好序
{
ptemp=head->next//ptemp指向未排好序的第一个结点
head->next=ptemp->next//
ptemp->next=p1//ptemp也排好序了,ptemp变成排好序的第一个结点了
p1=ptemp//再次让p1成为第一个排好序的结点
}
return p1//头结点为第一个结点
}
void create_menu()
//功能:输出功能菜单,提供人-机接口
{
char menu_Num
STUDENT *head=NULL
char ch
char file_name[256]
while(1)
{
system("cls")
cout<<"\t\t学生成绩管理系统\n"
cout<<"##########################################\n"
cout<<"#\t\t 1.新增学生信息\t\t #\n"
cout<<"#\t\t 2.加载数据库\t\t #\n"
cout<<"#\t\t 3.删除学生信息\t\t #\n"
cout<<"#\t\t 4.保存学生信息\t\t #\n"
cout<<"#\t\t 5.数据库查询\t\t #\n"
cout<<"#\t\t 6.原序输出\t\t #\n"
cout<<"#\t\t 7.排序输出\t\t #\n"
cout<<"#\t\t 8.退出\t\t\t #\n"
cout<<"##########################################\n"
cout<<"请输入操作编号:"
cin>>menu_Num
switch (menu_Num)
{
case '1':
free_link(head)//释放链表空间
head=new_student()//新增学生信息
break
case '2':
free_link(head)//释放链表空间
cout<<"请输入要加载的数据库文件的路径"<<endl
cin>>file_name
head=create_linkbyfile(file_name)//读取数据文件
if(head!=NULL)
{
cout<<"数据库"<<file_name<<"已加载"<<endl
Sleep(DELAYTIME)
}
break
case '3':
del_info(head)//删除学生信息
break
case '4'://保存学生信息
if (head==NULL)
{
cout<<"请先生成学生信息"<<endl
Sleep(DELAYTIME)
}
else
{
cout<<"想将学生信息保存到哪个数据库文件?"
cin>>file_name
cout<<"请选择保存方式:0追加到文件末尾 1覆盖文件\n"
cin>>menu_Num
if(save_info(file_name,head,menu_Num-'0')==0)//0表示追加,1表示覆盖
{
cout<<"信息保存失败\n"
}
else
{
cout<<"数据已保存到"<<file_name<<endl
Sleep(DELAYTIME)
}
}
break
case '5':
find_infile_printf(FILENAME)//数据库查询
break
case '6'://原序输出信息
pri_whole_link(head)
cout<<"返回主菜单? Y/N\t"
do
{
cin>>ch
}while(ch!='Y'&&ch!='y')
break
case '7'://排序输出信息
do
{
if((head=printf_sort(head))==NULL)
{
cout<<"数据库未加载"<<endl
Sleep(DELAYTIME)
break
}
else
{
cout<<"选择其他方式排序? Y/N\t"
cin>>ch
}
}while(ch=='Y'||ch=='y')
break
case '8':
free_link(head)//释放链表空间
exit(0)
break
default:
cout<<"输入有误!请重新输入!"<<endl
Sleep(DELAYTIME)
break
}
}
}
STUDENT * new_student()
//功能:创建学生信息(通过链表)
//返回值:头结点指针
{
STUDENT *pnew,*p,*head
float *pfloat
char ch
head=NULL
do
{
system("cls")
pnew=(STUDENT *)malloc(sizeof(STUDENT)*1)
cout<<"请输入学生的学号(0表示取消): "
cin>>pnew->num
if(0>=pnew->num)
{
break
}
cout<<"请输入学生的姓名:"
cin>>pnew->name
while(1)
{
cout<<"请输入学生的性别:0/1\t"
cin>>pnew->sex
if(pnew->sex&&pnew->sex-1)
{
cout<<"性别输入错误,0表示女性,1表示男性,请重新输入"<<endl
}
else
{
break
}
}
cout<<"请依次输入学生的数学、英语、政治、语文成绩:"<<endl
for(pnew->total=0,pfloat=&pnew->mathpfloat<&pnew->math+4)
{
cin>>*pfloat
if(*pfloat<0||*pfloat>150)
{
cout<<"成绩输入错误,只能为0~150"<<endl
}
else
{
pnew->total+=*pfloat
pfloat++
}
}
if(head==NULL)
{
head=pnew
}
else
{
p->next=pnew
}
p=pnew
pnew->next=NULL
cout<<"##########################该学生信息已生成#########################\n"
cout<<"建立另一个学生的信息? Y/N\t"
cin>>ch
}while(ch=='Y'||ch=='y')
return head
}
STUDENT* create_linkbyfile(char *filename)
//功能:读取文件,创建链表
//参数:如果filename不为空,则打开该文件,如果filename为空,要求输入文件位置
//创建的链表的所有结点的next全部修改,指向物理地址上的下一个结点
{
system("cls")
FILE *fp
STUDENT *head,*ptemp,*pnew
head=NULL//初始化head为空
if(filename==NULL)//若filename为空,要求输入文件绝对地址
{
char file_name[256]
cout<<"请输入数据库文件的路径:"<<endl
cin>>file_name
if(NULL==(fp=fopen(file_name,"rb")))
{
cout<<"数据库连接失败\n"
return 0
}
}
else
{
if(NULL==(fp=fopen(filename,"rb")))
{
cout<<"数据库连接失败\n"
return 0
}
}
for(ptemp=NULL)
{
pnew=(STUDENT *)malloc(sizeof(STUDENT)*1)
if(fread(pnew,sizeof(STUDENT),1,fp)!=NULL)
{
if(ptemp!=NULL)
{
ptemp->next=pnew
}
else
{
head=pnew
}
ptemp=pnew
}
else
{
if(ptemp!=NULL)
{
ptemp->next=NULL
}
else
{
head=NULL
}
free(pnew)
break
}
}
fclose(fp)
return head
}
STUDENT *del_info(STUDENT *head)
//根据学号,删除链表的结点
{
system("cls")
STUDENT *p1,*p2
int num
if (head==NULL)
{
cout<<"数据库未加载"<<endl
Sleep(DELAYTIME)
return 0
}
cout<<"请输入要删除学生的学号:"
cin>>num
for(p1=headp1!=NULL)
{
if(p1->num==num)//找到
{
if(p1==head)//要删除的结点是头结点
{
head=p1->next
}
else
{
p2->next=p1->next
}
cout<<"成功删除!!"
}
p2=p1
p1=p1->next
}
return head
}
int save_info(char *filename,STUDENT *head,int flag)
//功能:将链表按Binary写入文件末尾
//参数:
//1.filename文件名,绝对地址
//2.head指向链表的头结点
//3.flag 0追加或1覆盖数据
//返回值:失败则返回0
{
system("cls")
FILE *fp
STUDENT *p
char openmethod[8]
if(flag==0)
{
strcpy(openmethod,"ab+")//追加
}
else
{
strcpy(openmethod,"w")//覆盖
}
if(NULL==(fp=fopen(filename,openmethod)))//
{
cout<<"数据库连接失败"<<endl
Sleep(DELAYTIME)
return 0
}
else
{
for(p=headpp=p->next)
{
if((fwrite(p,sizeof(STUDENT),1,fp))==NULL)
{
cout<<"数据库创建失败"<<endl
return 0
}
}
}
fclose(fp)
return 1
}
int find_infile_printf(char *filename)
//功能:根据学号和姓名来查询某个学生
//参数:filename数据库文件
//返回值:失败返回0
//直接搜索文件,缺点是速度慢
//也可先根据文件创建链表,再搜索链表,缺点是如果文件较大,占用内存多
{
system("cls")
FILE *fp
STUDENT stu
int num
char stu_name[64]
char ch
if(filename==NULL)
{
return 0
}
do
{
memset(stu_name,0,sizeof(stu_name))
cout<<"查询学号或查询姓名? 1查询学号 0查询姓名"
//flag=1根据学号来查询,flag=0根据姓名来查询
cin>>num
if(num==1)
{
cout<<"输入要查询的学号:"
cin>>num
cout<<"正在为您查询学号为"<<num<<"的学生……"<<endl
}
else if(num==0)
{
cout<<"输入要查询的姓名:"
cin>>stu_name
cout<<"正在为您查询姓名为"<<stu_name<<"的学生……"<<endl
}
else
{
cout<<"输入有误"<<endl
return 0
}
if(NULL==(fp=fopen(filename,"rw")))
{
cout<<"数据库连接失败\n"
return 0
}
else
{
while(fread(&stu,sizeof(STUDENT),1,fp)!=NULL)
{
if(strcmp(stu.name,stu_name)==0||stu.num==num)
{
cout<<"学号\t姓名\t性别\t数学\t英语\t政治\t语文\t总成绩\n"
//输出该学生的所有信息
cout<<stu.num<<"\t"<<stu.name<<"\t"<<stu.sex<<"\t"<<stu.math<<"\t"<<stu.english<<"\t"<<stu.politic<<"\t"<<stu.chinese<<"\t"<<stu.total<<endl
//不加break可支持多个相同数据的索引
}
}
}
cout<<"##########################查询完毕#########################\n"
cout<<"查询另一个学生的信息? Y/N\t"
cin>>ch
}while(ch=='Y'||ch=='y')
fclose(fp)
return 1
}
int pri_whole_link(STUDENT *head)
//功能:显示整条链表的学生信息
//参数:head 头结点指针,如果head为空,返回空
{
system("cls")
STUDENT* p
if (head==NULL)
{
cout<<"数据库未加载"<<endl
Sleep(DELAYTIME)
return 0
}
cout<<"学号\t姓名\t性别\t数学\t英语\t政治\t语文\t总成绩\n"
for(p=headpp=p->next)
{
cout<<p->num<<"\t"<<p->name<<"\t"<<p->sex<<"\t"<<p->math<<"\t"<<p->english<<"\t"<<p->politic<<"\t"<<p->chinese<<"\t"<<p->total<<endl
}
return 1
}
STUDENT* printf_sort(STUDENT *head)
//功能:根据学号|某科目成绩|总成绩对链表进行排序,然后输出
//参数:head链表头指针,如果head为空,返回空
//返回值:返回新的链表的头结点指针
{
system("cls")
STUDENT *p1,*p2,*ptemp,*pfinished=NULL
char num
char flag
if (head==NULL)
{
return 0
}
cout<<"选择排序依据 0.数学成绩1.英语成绩2.政治成绩3.语文成绩4.总成绩\n"
while(1)
{
cin>>num
if(num>'4'||num<'0')
{
cout<<"输入有误,请重新输入 0~4"<<endl
}
else
{
break
}
}
cout<<"升序/降序输出? 0.降序1.升序"
while(1)
{
cin>>flag
if(flag>'1'||flag<'0')
{
cout<<"输入有误,请重新输入 0~1"<<endl
}
else
{
break
}
}
for(p1=headp1->next!=pfinished)//对链表进行从大到小排序(这里用冒泡法)
//p1使之总是指向头结点,pfinished使之总是指向已排序好的最前面的结点
//ptemp作为中介,保存p2的上一个结点
{
for(p2=p1p2->next!=pfinished)
{
if(*(&(p2->math)+num-'0')<*(&(p2->next->math)+num-'0'))//p2的值小于p2->next的值,交换 ptemp p2 p2->next
{
if(p2==p1)//头结点要交换
{
p1=p2->next
p2->next=p1->next
p1->next=p2
ptemp=p1
}
else
{
ptemp->next=p2->next
ptemp=p2->next
p2->next=ptemp->next
ptemp->next=p2
}
}
else//不需要交换,则p2、ptemp前进1位
{
ptemp=p2
p2=p2->next
}
}
pfinished=p2
}
if(flag=='1')
{
p1=reverse(p1)
}
pri_whole_link(p1)
cout<<"##########################信息显示完毕#########################\n"
return p1
}
void free_link(STUDENT *head)
//释放链表空间,如果head,什么都不做
{
STUDENT *p1,*p2
for(p1=headp1p1=p2)
{
p2=p1->next//先保存,否则
free(p1)//free后 p1->next数据丢失
}
}