#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; typedef struct XscjNode{ char NO[10]; char Name[16]; char Mtel[11]; char Email[16]; char BornAddr[20]; float AScore; float BScore; struct XscjNode *next; }XscjList,*XscjLink; void menu(){ cout<<" "<<endl; cout<<" "<<endl; cout<<" "<<endl; cout<<" |-----------------------------------------------------------------------------|"<<endl; cout<<" |菜单目录。实现如下学生成绩管理的设计要求: |"<<endl; cout<<" |1.实现创建学生成绩链表函数 Build 。 |"<<endl; cout<<" |2.实现函数Update,将姓名为Name的学生的A分成绩改为ScoreA。 |"<<endl; cout<<" |3.实现函数Insert,插入学号为NO,姓名为Name学生信息,将链表中学号≤NO的结点放 |" <<"\n"<<" |到该结点的前面,将学号>NO的结点放到该结点后面。 |"<<endl; cout<<" |4.实现函数Sort,将该学生按照B分成绩进行非递减排序。 |"<<endl; cout<<" |5.实现函数Merge,将两个按B分成绩非递减排序的学生成绩单合并为一个按B分成绩非 |" <<"\n"<<" |递增排序的通讯录,B分成绩相同且学号相同的成绩记录在结果中只保留一个。 |"<<endl; cout<<" |6.实现函数Count;统计籍贯是“广州”的学生人数。 |"<<endl; cout<<" |7.实现函数MoveK,将学生的成绩链表中倒数第k个结点之后的所有结点移到头结点后面 |" <<"\n"<<" |(保持结点间的先后顺序)。 |"<<endl; cout<<" |8.实现函数ReverseN,将学生成绩链表的正中间位置结点之后的全部结点倒置。 |"<<endl; cout<<" |输入1-8实现相应要求,输入0结束。请输入: |"<<endl; cout<<" |-----------------------------------------------------------------------------|"<<endl; } void Build(XscjLink &T){ /** fread ?**/ T=(XscjLink)malloc(sizeof(XscjList)); T->next=NULL; //头结点 XscjLink p; p=T; //遍历链表,向下传递 char filename[20]; FILE *fp; cout<<"创建一个学生成绩链表,学生数据以文件形式输入,输入文件名:"<<endl; cin>>filename; getchar(); while((fp=fopen(filename,"r"))==NULL){ cout<<"无法打开文件!重新输入文件名:"<<endl; cin>>filename; getchar(); } while(feof(fp)==0){ //空txt 空链表 p->next=(XscjLink)malloc(sizeof(XscjList)); fscanf(fp,"%s %s %s %s %s %f %f",p->next->NO,p->next->Name,p->next->Mtel,p->next->Email,p->next->BornAddr,&p->next->AScore,&p->next->BScore); p=p->next; //&q->NO——>整个数组内存的首地址 } fclose(fp); p->next=NULL; } void Update(XscjLink &T,char *Name,float ScoreA){ XscjLink p; p=T->next; if(T->next==NULL){ cout<<"学生信息链表为空,无法修改学生成绩!"<<endl; exit(1); } while(1){ if(p==NULL){ cout<<"未找到名为"<<Name<<"的同学!"<<endl; break; } else if(strcmp(p->Name,Name)==0){ p->AScore=ScoreA; cout<<"学生A分成绩修改成绩成功!"<<endl; break; } else{ p=p->next; } } } void OutPut(XscjLink T){ XscjLink p; int num=1; p=T->next; if(p==NULL){ cout<<"学生信息链表为空,无数据输出!"<<endl; exit(1); } while(1){ if(p==NULL){ cout<<"学生信息输出完毕!"<<endl; break; } else{ printf("第%d名学生信息:\n",num); printf("学号为%s ;",p->NO); printf("姓名为%s ;",p->Name); printf("手机号为%s ;",p->Mtel); printf("邮箱地址为%s ;",p->Email); printf("籍贯为%s ;",p->BornAddr); printf("A分成绩为%.2f分,",p->AScore); printf("B分成绩为%.2f分。\n",p->BScore); p=p->next; num++; } } } void Insert(XscjLink &T,char *Name,char *NO){ XscjLink p,q,pfront; p=T->next; pfront=T; q=(XscjLink)malloc(sizeof(XscjList)); strcpy(q->NO,NO); strcpy(q->Name,Name); strcpy(q->BornAddr,"未知"); strcpy(q->Email,"未知"); strcpy(q->Mtel,"未知"); q->AScore=q->BScore=0; while(p->next!=NULL){ if(strcmp(p->NO,NO)<=0){ p=p->next; pfront=pfront->next; } else{ break; } } //跳出循环情况有两种:尾结点;中间有大于NO的结点 if(p->next==NULL){//p指向尾结点,但未经过比较 if(strcmp(p->NO,NO)<0){ p->next=q; q->next=NULL; } else /*(strcmp(p->NO,NO)>0)*/{ pfront->next=q; q->next=p; } } else /*(strcmp(p->NO,NO)>0)*/{ pfront->next=q; q->next=p; } cout<<"学生信息插入完毕!"<<endl; } int Count(XscjLink T,char BornAddr[20]){ int num=0; XscjLink p; p=T->next; if(p==NULL){ cout<<"学生信息链表为空,无法统计人数!"<<endl; exit(1); } while(p->next!=NULL){ if(strcmp(p->BornAddr,BornAddr)==0){ num++; } p=p->next; } if(strcmp(p->BornAddr,BornAddr)==0){ num++; } return num; } void Sort(XscjLink &T){ XscjLink p,pf,pb,sign,temp;//sign作为外层循环判断条件 temp存储中间变量 p为具体调换结点指针 pf、pb分别为p结点前后节点指针,便于交换 p=T->next; pf=T; pb=p->next; sign=NULL; while(pb!=sign){ while(pb!=sign){ if(p->BScore>=pb->BScore){ //cout<<"进行一次交换"<<endl; temp=pb->next; pf->next=pb; pb->next=p; p->next=temp; pf=pf->next; pb=p->next; } else{ p=p->next; pf=pf->next; pb=p->next; } } sign=p; p=T->next; pf=T; pb=p->next; } } void Merge(XscjLink &T1,XscjLink &T2){ Sort(T1); Sort(T2); XscjLink p1,p2,t,temp,p; t=T1; p1=T1->next; p2=T2->next; if(p1->BScore<p2->BScore){//先顶头结点后的第一个结点,并且指为next域为NULL temp=p1; p1=p1->next; t->next=temp; temp->next=NULL; } else if(p1->BScore<p2->BScore){//<、>时正常链接 temp=p2; p2=p2->next; t->next=temp; temp->next=NULL; } else{//B分相等 if(strcmp(p1->Name,p2->Name)==0){//是否为同一人 temp=p1; p1=p1->next; t->next=temp; temp->next=NULL; p2=p2->next; } else{//不是同一人,B分成绩相等 temp=p1; p1=p1->next; t->next=temp; temp->next=NULL; } } while(p1&&p2){ //链接T1、T2需要比较的结点 进行类似先前的第一个数结点的比较操作 if(p1->BScore<p2->BScore){ temp=p1; p1=p1->next; temp->next=T1->next; T1->next=temp; } else if(p1->BScore>p2->BScore){ temp=p2; p2=p2->next; temp->next=T1->next; T1->next=temp; } else{ if(strcmp(p1->Name,p2->Name)==0){ temp=p1; p1=p1->next; temp->next=T1->next; T1->next=temp; p2=p2->next; } else{ temp=p1; p1=p1->next; temp->next=T1->next; T1->next=temp; } } } p=p1==NULL?p2:p1; //链接剩下结点,找到那个指针先NULL,链接另一个的结点p=p->next 循环进行 while(p){ temp=p; p=p->next; temp->next=T1->next; T1->next=temp; } } void MoveK(XscjLink &T,int k){ XscjLink p,q,pf,qf,temp; int cout=0; p=T->next; q=T->next; pf=T; qf=T; while(p!=NULL){ cout++; if(cout>k){ qf=qf->next; q=q->next; } p=p->next; pf=pf->next; } temp=T->next; T->next=q; pf->next=temp; qf->next=NULL; } void ReverseN(XscjLink &T){ XscjLink pm,pl,pmf,plf,temp; pm=pl=T->next; pmf=plf=T; while(pl!=NULL){ pm=pm->next; pmf=pmf->next; pl=pl->next->next; plf=plf->next->next; } temp=pm; pm=pm->next; pmf->next=temp; temp->next=NULL; while(pm!=NULL){ temp=pm; pm=pm->next; temp->next=pmf->next; pmf->next=temp; } } int main(){ int goal; menu(); cin>>goal; getchar(); while(goal!=1){ cout<<"没有链表存在无法进行其他操作!重新输入:"<<endl; cin>>goal; getchar(); } while(goal!=0) switch(goal){ case 1: cout<<"实现Build函数。"<<endl; XscjLink T; Build(T); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 2: cout<<"实现Update函数,修改学生A分成绩。输入学生姓名和修改A分成绩:"<<endl; char name[16]; float ScoreA; cin>>name>>ScoreA; getchar(); Update(T,name,ScoreA); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 3: cout<<"实现Insert函数,以学号NO插入某学生信息。输入要插入的信息即姓名和学号(空格分开):"<<endl; char Name[16]; char NO[10]; cin>>Name>>NO; getchar(); Insert(T,Name,NO); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 4: cout<<"实现Sort函数,将学生信息链表以B分成绩进行非递减排序。"<<endl; Sort(T); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 5: cout<<"实现Merge函数,将两个按B分成绩非递减排序的学生成绩链表合并为按B分成绩非递增排序的链表。"<<endl; cout<<"该操作需要建立另一个学生信息链表"<<endl; XscjLink P; Build(P); OutPut(P); cout<<"实现合并操作,归并至第一个链表"<<endl; Merge(T,P); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 6: cout<<"实现Count函数,统计某籍贯的学生总人数。输入要统计的籍贯:"<<endl; char BornAddr[20]; cin>>BornAddr; getchar(); cout<<"籍贯为"<<BornAddr<<"的总人数为"<<Count(T,BornAddr)<<"人!"<<endl; cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 7: cout<<"实现MoveK函数,将学生成绩链表中倒数第k个结点之后的所有结点移到头结点后面(保持结点间的先后顺序)。输入k的值:"<<endl; int k; cin>>k; getchar(); MoveK(T,k); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; case 8: cout<<"实现ReverseN函数,将学生成绩链表的正中间位置结点之后的全部结点倒置。"<<endl; ReverseN(T); OutPut(T); cout<<"回车继续......"<<endl; getchar(); menu(); cin>>goal; getchar(); break; default:break; } cout<<"实验操作结束!"<<endl; return 0; } 1.运用了少量的C文件操作技术,注意理解 2.大多函数操作较于简单,主要思想就是遍历单链表,其中有关结点交换连接的问题,注意指针操作确实对链表进行了影响 3.对于MoveK和ReverseN函数,由于对时间复杂度进行了限制,要有一定的巧妙的思想
时间: 2024-10-11 09:24:43