手机版
您的当前位置: 诚达文秘网 > 范文大全 > 公文范文 > 数据结构课程设计报告多关键字排序高考排序

数据结构课程设计报告多关键字排序高考排序

来源:公文范文 时间:2023-10-19 09:40:36

XX工 学 院 计算机工程学院 课程设计报告 设计名称:
数据结构课程设计 选题名称:
多关键字排序 姓 名:
学 号:
专业班级:
网络工程 系 (院):
计算机工程学院 设计时间:
设计地点:
软件工程实验室、教室 成绩:
指导教师评语:
签名:
年 月 日 1.课程设计目的 1、训练学生灵活应用所学数据结构知识,独立完成问题分析,结合数据结构理论知识,编写程序求解指定问题。

2.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;

3.提高综合运用所学的理论知识和方法独立分析和解决问题的能力;

4.训练用系统的观点和软件开发一般规范进行软件开发,巩固、深化学生的理论知识,提高编程水平,并在此过程中培养他们严谨的科学态度和良好的工作作风。

2.课程设计任务与要求:
任务 题目:多关键字的排序 【问题描述】 多关键字的排序有其一定的实用范围。例如:在进行高考分数处理时,除了需对总分进行排序外,不同的专业对单科分数的要求不同,因此尚需在总分相同的情况下,按用户提出的单科分数的次序要求排出考生录取的次序。

【基本要求】 (1)假设待排序的记录不超过10000,表中记录的关键字数不超过5,各个学科关键字的范围均为0至100,总分关键字的范围是0-300。按用户给定的进行排序的关键字的优先关系,输出排序结果。

(2)约定按LSD法进行多关键字的排序。在对各个关键字进行排序时采用两种策略:其一是利用稳定的内部排序法,其二是利用“分配”和“收集”的方法。并综合比较这两种策略。

【测试数据】 由随机数产生器生成。

【实现提示】 由于是按LSD方法进行排序,则对每个关键字均可进行整个序列的排序,但在利用通常的内部排序方法进行排序时,必须选用稳定的排序方法 要求:
1、在处理每个题目时,要求从分析题目的需求入手,按设计抽象数据类型、构思算法、通过设计实现抽象数据类型、编制上机程序和上机调试等若干步骤完成题目,最终写出完整的分析报告。前期准备工作完备与否直接影响到后序上机调试工作的效率。在程序设计阶段应尽量利用已有的标准函数,加大代码的重用率。

2、.设计的题目要求达到一定工作量(300行以上代码),并具有一定的深度和难度。

3、程序设计语言推荐使用C/C++,程序书写规范,源程序需加必要的注释; 4、每位同学需提交可独立运行的程序;

5 、每位同学需独立提交设计报告书(每人一份),要求编排格式统一、规范、内容充实,不少于10页(代码不算);

6、课程设计实践作为培养学生动手能力的一种手段,单独考核。

3.课程设计说明书 一 需求分析 1)选题功能分析 【题目的意义】 1、 对高考分数按照总分和不同学科的分数按照优先级顺序排出考生录取的次序,以满足不同专业对单科分数的要求。

2、 对不同排序策略进行综合比较。

【实现的功能】 1、 用C语言设计实现一个高考成绩排序系统。

2、 创建模拟的高考考生成绩表,存放到txt文档中。考生考号为1,2,3…用伪随机数生成器生成各考号学生的各个学科成绩,并计算总分成绩。

3、 由于实际中高考考生成绩表是已知的(模拟创建的txt文档),程序能从文件中读取数据。从创建的考生成绩表中读取数据,并对数据处理 4、 按照学科的优先级顺序,对学生的成绩排序。既可以以某一学科的单科成绩优先级最高排序,也可以先按总分优先级最高来排序。

5、 在对各个关键字即单科成绩进行排序的时候,分别用稳定的内部排序法(冒泡法)以及“‘分配’和‘搜集’”的方法进行排序。

6、 能够对冒泡法排序策略和“‘分配’和‘搜集’”方法排序策略进行的执行时间进行比较。

7、 输入数据:1各科英文首字母的代号,字符型,如smce 2整型数,0-10000 1输出程序用两种方法进行排序的进程和执行时间 2输出前n名学生的信息 二 概要设计 1、 伪随机生成的数据包含语文、数学、英语三科成绩。总成绩为语文、数学、英语三科成绩的和。学号按成绩数组的下标赋值,生成学生成绩记录,将该记录保存到txt文档中 2、 从上面的txt文档中读取数据到一个二维数组中,以便对学生信息进行处理 3、 给出排序的优先关系,根据优先关系由低位向高位逐个关键字进行排序。

4、 对单科成绩进行排序的时候,单科成绩虽然是0-100,但总成绩是0-300,所以要建301个队列进行排序,先按“分配”和“搜集”的方法进行一趟“基数排序”;
然后再按照稳定的内部排序法(冒泡法)进行排序。将搜集好的或排序好的序列存储,以进行对次优先级的关键字进行再排序。

5、 将排序好的学生成绩按照用户提出的提取人数的要求,保存到另一个txt文档中,并输出到屏幕 6、 系统用到的抽象数据类型定义 double BubTime1, //按第一个关键字代表的学科成绩用冒泡法排序执行的时间 BubTime2, BubTime3, BubTime4, BubTimeSum, //冒泡法排序的总时间 DCTime1, //按第一个关键字代表的学科成绩用分配和收集的方法执行的时间 DCTime2, DCTime3, DCTime4, DCTimeSum; //分配和收集法排序的总时间 int score[10000][5], //随机创建的模拟学生记录源数组 bubble[10000][5], //进行冒泡法排序时用来存放学生记录源数组,并且随排序进行数组中的记录发生交换 copy[10000][5]; //从模拟的学生记录源txt文件中读取学生记录到该数组 struct LSD d[301]; //分配数组,该处考虑到把总分(0-300)也列入优先级序列中,因此建立了301个队列 int *c[10000]; //用来存放收集到的学生记录 char x[5]; //存放有优先关系的学科代号序列 7、 系统中的各个函数模块 1:void CreatScore(int score[10000][5]); //随机创建学生记录表score。正常高考中该表是已知的,不必创建 2:void Collect(struct LSD d[301],int *c[10000]); //LSD法排序中的收集函数,即将分配好的记录收集到c指针数组保存 3:void InitDivide(struct LSD d[301]); //用于初始化临时分配数组,在每一次收集后必须做的工作 4:double DCSort(struct LSD d[301],int *c[10000],int n); //分配(Divide)和收集(Collect)排序的方法 5:double BubbleSort(int score[10000][5],int n); //冒泡法排序 6:void Print(); //将排序结果文件中的记录数据输出到屏幕上 7:void savesources(int score[10000][5],int n); //将模拟创建的高考学生信息记录存放到文件中 8:void saveresults(int score[10000][5],int n); //按照用户的要求(总成绩在前多少名的学生记录),将这n条学生的记录存放到新的文件中 9:void load(int score[10000][5]); //从学生高考记录源文件中读取记录到该二维数组中 8、 各函数之间的调用关系 1:主函数可以调用除子函数2之外的所有函数 2:子函数4可以调用子函数2和3 【功能模块图】 M A I N InitDivide(d) CreateScore(score) Savesources(score.10000) Lode(copy) DcSort(d,c,0) 返回执行时间 Collect(d,c) InitDivide(d) BubbleSort(bubble,0) 返回执行时间 Saveresults(bubble,n) Print() 三 详细设计 1.抽象数据类型:
该数据类型是在分配和收集的时候存放分配成绩数组 1’ 抽象数据类型struct LSD struct LSD//队列的结构类型,链表存储结构类型 { int *cur;//当前位置 struct LSD *next;//队列中下一个位置 }; 2’ CreatScore(int score[RecordNumber][KeyNumber])函数 /*创建一个含有RecordNumber名学生成绩记录的score,包含语文、数学、英语、总分和学号,随机生成语文、数学、英语的成绩。

*传递的参数是成绩数组score,无返回值 */ void CreatScore(int score[RecordNumber][KeyNumber]) { /*伪随机生成语文、数学、英语的成绩*/ for(i=0;i< RecordNumber;i++) { for(j=0;j<3;j++) { score[i][j]=rand()%101; //成绩的范围是0-100 } } /*总分成绩初始化*/ for(i=0;i< RecordNumber;i++) { score[i][3]=score[i][0]+score[i][1]+score[i][2]; //总成绩为各科成绩之和 } /*学号的初始化*/ for(i=0;i< RecordNumber;i++) score[i][4]=i+1; //学号是按从前到后的顺序依次赋值的 } start 创建Score[1000][5] 含语文、数学、英语、总分和学号 伪随机生成语文、数学、英语的成绩 初始化总分 生成学号,按从前到后顺序 结束 3’收集函数Collect(struct LSD d[QueueNumber],int *c[RecordNumber]) /*将分配好的成绩数组d,收集到c指针数组保存 * 传递的参数为分配好的数组d和收集的指针数组c,无返回值 */ void { struct LSD *p; for(i=QueueNumber-1; i>=0; i--) { if(d[i].cur!=NULL) //当前队列不空,即有学生的成绩分配到该队列 { p=&d[i]; while(p->cur!=NULL) //当前位置有学生的成绩 { c[j]=p->cur; //收集到c指针数组中 j++; p=p->next; //指针p指向该队列的下一个位置 } } } } 当前位置有学生的成绩开始 初始化指针数组 建立300个队列 队列为空 Y N 当前位置学生的成绩收集到指针数组中 指针p指向该队列的下一个位置 结束 4’初始化分配数组InitDivide(struct LSD d[QueueNumber]) /*初始化d数组即置空,在每一次收集后必须做的工作 *传递的参数是struct LSD d[QueueNumber],无返回值 */ void InitDivide(struct LSD d[QueueNumber]) { for(int i=0;i<QueueNumber;i++) { d[i].cur=NULL; d[i].next=NULL; } } 5’“分配“和“收集“方法排序double DCSort(struct LSD d[QueueNumber],int *c[RecordNumber],int n) /*“分配“和“收集“方法排序 *分配数组为d,收集数组为c *进行排序的关键字所代表的学科成绩n在分配数组中的位置就是n *传递的参数是分配数组struct LSD d[QueueNumber],用来收集的指针数组int *c[RecordNumber],关键字代表的学科在数组中的下标 */ double DCSort(struct LSD d[QueueNumber],int *c[RecordNumber],int n) { /*按关键字代表的学科成绩将成绩分配到d中*/ for(j=0;j<RecordNumber;j++) { temp=c[j][n]; //学生的成绩就是队列号 if(d[temp].cur==NULL) //当前队列为空 { d[temp].cur=c[j]; //将c[j]代表的学生的成绩添加到该队列中 p=&d[temp]; p1=(struct LSD *)malloc(LENGTH); p1->cur=NULL; p1->next=NULL; p->next=p1; //初始化刚刚添加了学生记录的队列 } else //当前队列不为空 { p=&d[temp]; /*循环,一直到队列的结尾*/ while(p->cur!=NULL) p=p->next; p->cur=c[j]; //将c[j]代表的学生的成绩添加到该队列中 p1=(struct LSD *)malloc(LENGTH); //新申请一个空间来存放学生成绩 p1->cur=NULL; p1->next=NULL; p->next=p1; } } //分配完毕 Collect(d,c); //将分配好的成绩序列收集到c中 InitDivide(d); //初始化分配数组 return time; //返回执行时间 } 6’冒泡法排序double BubbleSort(int bubble[RecordNumber][QueueNumber]) /*冒泡法排序 *传递的参数是学生成绩记录int bubble[RecordNumber][KeyNumber],关键字所代表学科成绩在数组中的下标 */ double BubbleSort(int bubble[RecordNumber][KeyNumber],int n) { for(int i=0;i<RecordNumber;i++) { for(int j=0;j<RecordNumber-1-i;j++) { if(bubble[j][n]<bubble[j+1][n]) { /*交换学生的各科成绩*/ for(int m=0;m<KeyNumber;m++) { temp=bubble[j][m]; bubble[j][m]=bubble[j+1][m]; bubble[j+1][m]=temp; } } } } return time; //返回排序执行的时间 }返回执行的时间 } 7’ Print()函数 /*从排序结果存放的文件recordresults.txt中读取记录输出到屏幕上 */ void Print() { FILE *fp; if((fp=fopen(“D:\\recordresults.txt“,“rb“))==NULL) printf(“文件打开失败!\n“); else printf(“文件打开成功!\n“); char t; while(fscanf(fp,“%c“,&t)&&!feof(fp)) { if(t!=EOF) printf(“%c“,t); } //如果读到结束符,循环结束,输出结束 fclose(fp); //关闭文件 } 8’ savesources(int score[RecordNumber][KeyNumber],int n) /*保存学生记录的函数 *参数为要保存的学生记录和记录条数 *无返回值 */ void savesources(int score[RecordNumber][KeyNumber],int n) { FILE *fp; //指向文件的指针 if((fp=fopen(“D:\\recordsources.txt“,“wb“))==NULL) //只写 { printf(“文件打开失败!\n“); exit(1); } fprintf(fp,“%d“,n); //将记录条数写入文件 fprintf(fp,“\r\n“); //将换行符号写入文件 for(i=0;i<n;i++) { fprintf(fp,“%-10d%-10d%-10d%-10d%-10d“, score[i][4],score[i][0],score[i][1],score[i][2],score[i][3]);//格式写入记录 fprintf(fp,“\r\n“); //将换行符号写入文件 } fclose(fp); } 9’ saveresults(int score[RecordNumber][KeyNumber],int n) /*保存学生记录的函数 *参数为要保存的学生记录和记录条数 *无返回值 */ void saveresults(int score[RecordNumber][KeyNumber],int n) { FILE *fp; //指向文件的指针 if((fp=fopen(“D:\\recordresults.txt“,“wb“))==NULL) //只写,打开或建立一个二进制文件,只允许写数据 { printf(“文件打开失败!\n“); exit(1); } fprintf(fp,“%d“,n); //将记录条数写入文件 fprintf(fp,“\r\n“); //将换行符号写入文件 for(i=0;i<n;i++) { fprintf(fp,“%-10d%-10d%-10d%-10d%-10d“, score[i][4],score[i][0],score[i][1],score[i][2],score[i][3]);//格式写入记录 fprintf(fp,“\r\n“); //将换行符号写入文件 } fclose(fp); } 10’ load(int score[RecordNumber][KeyNumber]) /*读入函数,把文件中的记录度入到二维数组中 *参数为结构体数组 */ void load(int score[RecordNumber][KeyNumber]) { FILE *fp; if((fp=fopen(“D:\\recordsources.txt“,“rt“))==NULL) //打开文件 { printf(“文件打开失败!\n“); exit(1); } fscanf(fp,“%d“,&n); //读入记录数 for(i=0;i<n;i++) fscanf(fp,“%d %d %d %d %d“, &score[i][4], &score[i][0], &score[i][1], &score[i][2], &score[i][3]); //按格式读入记录 fclose(fp); } 11’算法分析 1)
LSD算法:
这是一种“低位优先”的排序方法,借助一趟基数排序的方法,先按最低位的值对记录进行初步排序,在此基础上再按次低位的值进行进一步排序。以此类推,有低位到高位,每一趟都是在前一趟的基础上,根据关键字的某一位对所有的记录进行排序,直至最高位,这样就完成了基数排序的全过程。

从算法中可以看出,对于n个记录(每个记录含d个子关键字,每个子关键字的取值范围为RADIX个值)进行链式排序的时间复杂度为O(d(n+RADIX)),其中每一趟分配算法的时间复杂度为O(n),每一趟收集的算法的时间复杂度为O(RADIX),整个排序进行d趟分配和收集,所需辅助空间为2*RADIX个队列指针。由于需要链表作为存储结构,则相对于其他以顺序结构存储记录的排序方法而言,还增加了n个指针域的空间。

2)
冒泡法排序:
该排序是比较简单的交换类排序方法,通过相邻数据元素的交换,逐步将带排序列变成有序序列的过程。

最坏情况下,待排序的记录按关键字的逆序进行排列,此时,每一趟冒泡排序需要进行i次比较,3i次移动。经过n-1趟冒泡排序后,总的比较次数为N=∑i=n(n-1)/2,n=1,2,…,n-1.总的移动次数为3n(n-1)/2次,因此该算法的时间复杂度为O(n*n),空间复杂度为O(1)。另外,冒泡排序法是一种稳定的每部排序法。

四 测试成果 五 附录(源程序清单)
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> struct LSD //抽象类型定义,队列的结构类型,由于是按LSD法进行的排序,所以命名为LSD { int *cur; //当前位置 struct LSD *next; }; #define LENGTH sizeof(struct LSD) void CreatScore(int score[10000][5]); //随机创建学生记录表score。正常高考中该表是已知的,不必创建 void savesources(int score[10000][5],int n); //将模拟创建的高考学生信息记录存放到文件中 void load(int score[10000][5]); //从学生高考记录源文件中读取记录到该二维数组中 void Collect(struct LSD d[301],int *c[10000]); //LSD法排序中的收集函数,即将分配好的记录收集到c指针数组保存 void InitDivide(struct LSD d[301]); //用于初始化临时分配数组,在每一次收集后必须做的工作 double DCSort(struct LSD d[301],int *c[10000],int n); //分配(Divide)和收集(Collect)排序的方法 double BubbleSort(int score[10000][5],int n); //冒泡法排序 void saveresults(int score[10000][5],int n); //按照用户的要求(总成绩在前多少名的学生记录),将这n条学生的记录存放到新的文件中 void Print(); //将排序结果文件中的记录数据输出到屏幕上 int main() { double BubTime1, //按第一个关键字代表的学科成绩用冒泡法排序执行的时间 BubTime2, BubTime3, BubTime4, BubTimeSum, //冒泡法排序的总时间 DCTime1, //按第一个关键字代表的学科成绩用分配和收集的方法执行的时间 DCTime2, DCTime3, DCTime4, DCTimeSum; //分配和收集法排序的总时间 int score[10000][5], //随机创建的模拟学生记录源数组 bubble[10000][5], //进行冒泡法排序时用来存放学生记录源数组,并且随排序进行数组中的记录发生交换 copy[10000][5]; //从模拟的学生记录源txt文件中读取学生记录到该数组 struct LSD d[301]; //分配数组,该处考虑到把总分(0-300)也列入优先级序列中,因此建立了301个队列 int *c[10000]; //用来存放收集到的学生记录 char x[5]; //存放有优先关系的学科代号序列 /*初始化c,使其与score函数“同步“*/ for(int i=0;i<10000;i++) c[i]=score[i]; InitDivide(d); //初始化队列 /*在实际中全部学生的高考记录是存放在一个文件中的,程序运行时是从该文件中读取的源记录数据。

*本程序要求随机模拟创建该文件,所以下面要创建每个学生的记录(CreatScore())并保存到一个文件中(save())
*调用这两个函数后就生成了全部学生的记录 */ CreatScore(score); //伪随机生成各科成绩,并将考号和总成绩一并生成在score数组中 savesources(score,10000); //将随机生成的记录信息保存在record.txt中,该文件在程序运行的时候是不变的 load(copy); //从源记录文件record.txt中读取学生记录到数组copy中 /*为了防止改变源记录,在进行冒泡法排序的时候用bubble这个数组*/ for(i=0;i<10000;i++) for(int j=0;j<5;j++) bubble[i][j]=copy[i][j]; //将源记录赋值给bubble数组 printf(“请输入您要按照哪种优先级顺序对学生成绩进行排序:比如(总分,数学,语文,英语)\n就请输入smce(即各科的英文首字母序列)“); scanf(“%s“,x); //输入进行排序的关键字的优先序列 for(i=3;i>=0;i--) { printf(“\n\n现在程序正在按%c代表的学科进行成绩分配,请稍后…“,x[i]); switch(x[i]) { case 'c': //Chinese DCTime1=DCSort(d,c,0); //按语文这个关键字用分配和收集法排序,并返回时间 BubTime1=BubbleSort(bubble,0); //按语文这个关键字用冒泡法排序 break; case 'm': //Math DCTime2=DCSort(d,c,1); BubTime2=BubbleSort(bubble,1); break; case 'e': //English DCTime3=DCSort(d,c,2); BubTime3=BubbleSort(bubble,2); break; case 's': //Sum DCTime4=DCSort(d,c,3); BubTime4=BubbleSort(bubble,3); break; default: printf(“您输入的科目代号错误\n“); //输入代号错误提示 break; } } DCTimeSum=DCTime1+DCTime2+DCTime3+DCTime4; //分配排序法的总时间等于按照各个关键字进行排序的分时间的和 BubTimeSum=BubTime1+BubTime2+BubTime3+BubTime4; printf(“\n用分配和收集的方法排序,执行的总时间为:%.3f\n“,DCTimeSum); printf(“用冒泡法排序,执行的总时间为:%.3f\n“,BubTimeSum); printf(“\n请问您要提取多少条学生的成绩信息(0-10000):“); int n; scanf(“%d“,&n); saveresults(bubble,n); //将前n名学生的记录保存在结果文件recordresults.txt中 Print(); //从结果文件recordresults.txt中读取记录到屏幕上 return 0; } /*创建一个含有10000名学生成绩记录的score,包含语文、数学、英语、总分和学号,随机生成语文、数学、英语的成绩。

*传递的参数是成绩数组score,无返回值 */ void CreatScore(int score[10000][5]) { int i, j; srand(time(NULL)); //利用时间设置随机种子产生随机数 /*伪随机生成语文、数学、英语的成绩*/ for(i=0;i<10000;i++) { for(j=0;j<3;j++) { score[i][j]=rand()%101; //成绩的范围是0-100 } } /*总分成绩初始化*/ for(i=0;i<10000;i++) { score[i][3]=score[i][0]+score[i][1]+score[i][2]; //总成绩为各科成绩之和 } /*学号的初始化*/ for(i=0;i<10000;i++) score[i][4]=i+1; //学号是按从前到后的顺序依次赋值的 } /*保存学生记录的函数 *参数为要保存的学生记录和记录条数 *无返回值 */ void savesources(int score[10000][5],int n) { printf(“\n程序正在模拟创建10000条高考成绩记录并保存到文件D:\\recordresources.txt中,\n请稍后…\n“); //输出提示信息 int i; FILE *fp; //指向文件的指针 if((fp=fopen(“D:\\recordsources.txt“,“wb“))==NULL) //只写,打开或建立一个二进制文件,只允许写数据 { printf(“文件打开失败!\n“); exit(1); } fprintf(fp,“%d“,n); //将记录条数写入文件 fprintf(fp,“\r\n“); //将换行符号写入文件 for(i=0;i<n;i++) { fprintf(fp,“%-10d%-10d%-10d%-10d%-10d“,score[i][4],score[i][0],score[i][1],score[i][2],score[i][3]);//格式写入记录 fprintf(fp,“\r\n“); //将换行符号写入文件 } fclose(fp); printf(“文件创建并保存成功!\n您可以通过路径D:\\recordsources.txt进行查看。\n\n\n“); } /*读入函数,把文件中的记录度入到二维数组中 *参数为结构体数组 */ void load(int score[10000][5]) { int i, n; FILE *fp; if((fp=fopen(“D:\\recordsources.txt“,“rt“))==NULL) //打开文件 { printf(“文件打开失败!\n“); exit(1); } fscanf(fp,“%d“,&n); //读入记录数 for(i=0;i<n;i++) fscanf(fp,“%d %d %d %d %d“, &score[i][4], &score[i][0], &score[i][1], &score[i][2], &score[i][3]); //按格式读入记录 fclose(fp); printf(“********************************排序系统开始运行********************************\n“); printf(“首先是从模拟高考成绩源文件recordsources.txt中读取数据!\n正在读取数据,请稍后…\n“); printf(“成功从源文件中读取 %d 条记录到排序系统中\n\n“, n); } /*将分配好的成绩数组d,收集到c指针数组保存 * 传递的参数为分配好的数组d和收集的指针数组c,无返回值 */ void Collect(struct LSD d[301],int *c[10000]) { int i, j=0; struct LSD *p; for(i=300; i>=0; i--) //因为包含总成绩(0-300)的优先级,所以共分配的队列为0-300 { if(d[i].cur!=NULL) //当前队列不空,即有学生的成绩分配到该队列 { p=&d[i]; while(p->cur!=NULL) //当前位置有学生的成绩 { c[j]=p->cur; //收集到c指针数组中 j++; p=p->next; //指针p指向该队列的下一个位置 } } } } /*初始化d数组即置空,在每一次收集后必须做的工作 *传递的参数是struct LSD d[301] */ void InitDivide(struct LSD d[301]) { for(int i=0;i<301;i++) { d[i].cur=NULL; d[i].next=NULL; } } /*“分配“和“收集“方法排序 *分配数组为d,收集数组为c *进行排序的关键字所代表的学科成绩n在分配数组中的位置就是n *传递的参数是分配数组struct LSD d[301],用来收集的指针数组int *c[10000],关键字代表的学科在数组中的下标 */ double DCSort(struct LSD d[301],int *c[10000],int n) { double time; clock_t t_start; //时间记录的开始 clock_t t_end; //时间记录的结束 t_start=clock(); //获取排序开始的时间 int j, temp; struct LSD *p,*p1; /*按关键字代表的学科成绩将成绩分配到d中*/ for(j=0;j<10000;j++) { temp=c[j][n]; //学生的成绩就是队列号 if(d[temp].cur==NULL) //当前队列为空 { d[temp].cur=c[j]; //将c[j]代表的学生的成绩添加到该队列中 p=&d[temp]; p1=(struct LSD *)malloc(LENGTH); p1->cur=NULL; p1->next=NULL; p->next=p1; //初始化刚刚添加了学生记录的队列 } else //当前队列不为空 { p=&d[temp]; /*循环,一直到队列的结尾*/ while(p->cur!=NULL) p=p->next; p->cur=c[j]; //将c[j]代表的学生的成绩添加到该队列中 p1=(struct LSD *)malloc(LENGTH); //新申请一个空间来存放学生成绩 p1->cur=NULL; p1->next=NULL; p->next=p1; } } //分配完毕 printf(“\n分配完毕,下面开始进行收集,请稍后…\n“); Collect(d,c); //将分配好的成绩序列收集到c中 printf(“收集完毕。\n“); InitDivide(d); //初始化分配数组 t_end = clock(); //获取结束测试点的时间 time=(double)(t_end-t_start)/CLOCKS_PER_SEC; printf(“本次分配和收集用时: %.3f s\n“,time); return time; //返回执行时间 } /*冒泡法排序 *传递的参数是学生成绩记录int bubble[10000][5],关键字所代表学科成绩在数组中的下标 */ double BubbleSort(int bubble[10000][5],int n) { printf(“\n下面开始用冒泡法进行排序,请稍后…\n“); double time; clock_t t_start; clock_t t_end; t_start=clock(); int temp; for(int i=0;i<10000;i++) { for(int j=0;j<9999-i;j++) { if(bubble[j][n]<bubble[j+1][n]) { /*交换学生的各科成绩*/ for(int m=0;m<5;m++) { temp=bubble[j][m]; bubble[j][m]=bubble[j+1][m]; bubble[j+1][m]=temp; } } } } t_end = clock(); time=(double)(t_end-t_start)/CLOCKS_PER_SEC; printf(“本次冒泡法排序用时: %.3f s\n\n“,time); return time; //返回排序执行的时间 } /*保存学生记录的函数 *参数为要保存的学生记录和记录条数 *无返回值 */ void saveresults(int score[10000][5],int n) { int i; FILE *fp; //指向文件的指针 if((fp=fopen(“D:\\recordresults.txt“,“wb“))==NULL) //只写,打开或建立一个二进制文件,只允许写数据 { printf(“文件打开失败!\n“); exit(1); } fprintf(fp,“%d“,n); //将记录条数写入文件 fprintf(fp,“\r\n“); //将换行符号写入文件 for(i=0;i<n;i++) { fprintf(fp,“%-10d%-10d%-10d%-10d%-10d“,score[i][4],score[i][0],score[i][1],score[i][2],score[i][3]);//格式写入记录 fprintf(fp,“\r\n“); //将换行符号写入文件 } fclose(fp); } /*从排序结果存放的文件recordresults.txt中读取记录输出到屏幕上 */ void Print() { FILE *fp; if((fp=fopen(“D:\\recordresults.txt“,“rb“))==NULL) printf(“文件打开失败!\n“); else printf(“文件打开成功!\n“); char t; while(fscanf(fp,“%c“,&t)&&!feof(fp)) { if(t!=EOF) printf(“%c“,t); } //如果读到结束符,循环结束,输出结束 fclose(fp); //关闭文件 } 六 用户手册 本程序的运行环境为DOS系统,执行文件为“LSDSort.exe” 进入程序后的界面如下:
用户此时可以按路径D:\\recordresources.txt文档中查看模拟高考成绩表 自动计算出分配收集法和冒泡法分别所需要的时间,综合比较两种方法 按照提示输入自己要求的各个成绩的优先关系序列,然后程序自动进入排序系统,最后程序就将分配和收集的过程以及冒泡法排序的过程分别输出,最后得到排序结果。

然后会到下面的界面:
即提示用户输入录取的学生数目,由于把全部成绩输出对于高校录取并没有用,所以只要按一定的人数提取记录就可以了 4.课程设计心得 这次课程设计收获很大,从一开始的迷迷糊糊不明白题意,到现在很清楚该设计的各个方面,我在无数次的调试过程中学到了很多有用的东西 1、模块化的思想。使程序模块化之后,可以很方便的调用和对某个模块的修改,我由于一开始对题目的要求不到位,在最后验收的时候发现一些功能未实现的问题,如果我的程序很乱,函数之间没有清晰的调用关系,参数传递混乱的话,我就很难修改它,但是我用了模块化的思想,在很短的时间之内就将程序添加了文件流操作的功能,使程序更加满足实际要求,也更加清晰。现在可以很容易添加一个不同的功能模块。

2、调试技巧。在调试过程中同学们遇到了很多不同的错误,比如:错误提示如下 Cpp1.obj : error LNK2001: unresolved external symbol “void __cdecl CreatScore(int (* const)[5])“ (?CreatScore@@YAXQAY04H@Z) Debug/Cpp1.exe : fatal error LNK1120: 1 unresolved externals。根据以前的经验知道这是连接上出了错,而且以前遇到类似的错误是因为传递的参数不同而导致的,现在也想到估计是同样的问题,但是看程序,参数传递正常。后来在找CreatScore时发现我不知道什么时候把它剪切了,这就好像是声明了程序要用CreatScore,而且也用了,但是并没有说明CreatScore是什么,它是怎样实现的。

3、调试技巧。调试的时候我一般都是用F10和F20进行调试,问老师的时候又学到了设置断点的方法调试程序,这样可以通过猜想,对某一段代码进行调试,省去了很多步骤。

4、分析问题的技巧。这个和设置断点的方法类似,例如在判断打开文件是否成功时,由于有三个函数要打开和关闭文件,而且从无提示都一样:文件打开失败。这样在运行程序时,如果文件真的打开失败了,就很难知道哪块函数出问题了,所以可以设置不同的提示信息,来很清楚的追踪到程序的运行,还有就是发送错误报告,这种问题出现时总感觉不知道如何下手修改,因为很难知道错误的发生点,这是我们就可以设置输出提示信息:“程序已经运行到这里了”这样我们就可以从它是否输出该提示信息来了解程序是否正常运行到某个位置。

5、在修改错误的时候也要有至顶向下的修改方法,因为后面的错误很可能就是勤勉的定义错误,从上到下改,我们可以发现有时候错误从80多个一下子就变成两三个了,通过这个我们也可以看到不同的错误所影响的范围,对我们变成中的侧重点也有帮助 6、指针和地址的使用。在进行文件操作时,我有一个功能就是从文件中读取学生记录到一个二维数组中,感觉写的没错,可是输出来的结果总是一个符合格式要求的地址结果,经过老师的指导,我知道了在读取的时候应该把数据存放在数组的地址中,而我却是按赋值的错误想法做的。

7、冒泡法排序。我认为这个排序的算法很简单,所以用到的时候没有按照书上的算法,直接自己写了一个冒泡排序,而且一直深信我的这个排序是正确的,可是结果总是出现错误,排序结果并不正确,后来按照书上的算法做很正确。所以在程序设计时要对算法绝对重视,要考虑到很多可能的会出现的情况,必须详细具体。

8、参数的传递和程序中的计算问题。开始我用101个队列进行分配,但是都出现错误了,即排出的结果有个别变成了地址,而且有向同学好的考生的信息输出,调试了一天多也不知道到底是哪里出错了,后来发现错误很简单,我把总成绩也列入了排序中,而总成绩是三门学科的总成绩0-300,所以应该用301个队列分配。也不知道电脑是把总成绩都分配到那里了! 还有很多很多的收获,现在只能想到这些了,我想那些没想起来的会在我以后编程的过程中得到运用的,这些想起来的基本上都是花费了好长时间才解决的问题,也就是在编程中的死结,整个工作在这个关键点上停下来了,这时可以寻求帮助,我们会发现,原来这么简单。

诚达文秘网 https://www.rk1k.cn Copyright © 2019-2024 . 诚达文秘网 版权所有

Powered by 诚达文秘网 © All Rights Reserved. 备案号:浙ICP备19042126号-1

Top