1、基于插入排序方法的类模板设计与实现成 绩 评 定 表学生姓名郝晓鹏班级学号1103060129专 业通信工程课程设计题目基于插入排序方法的类模板设计与实现评语组长签字:成绩日期 20 年 月 日课程设计任务书学 院信息科学与工程专 业通信工程学生姓名郝晓鹏班级学号1103060129课程设计题目 基于插入排序方法的类模板设计与实现实践教学要求与任务建立一维数组数据结构的模板类,使一维数组中的数据元素可以是char, int, float等多种数据类型,并对数组元素实现插入类排序。主要完成如下功能:(1)实现数组数据的输入和输出;(2)实现直接插入排序功能;(3)实现2-路插入排序功能;(4)实
2、现希尔排序功能;(5)将每种排序功能作为类的成员函数实现,编写主函数测试上述排序功能。工作计划与进度安排第17周:分析题目,查阅课题相关资料,进行类设计、算法设计;第18周:程序的设计、调试与实现;第19周:程序测试与分析,撰写课程设计报告,进行答辩验收。指导教师: 201 年 月 日专业负责人:201 年 月 日学院教学副院长:201 年 月 日 摘 要排序是计算机程序设计中的一种重要运算,它的功能是将一个数据元素(或记录)的任意序列重新排列成一个按关键字有序的序列。简言之,所谓排序就是根据关键字值的非递减或非递增次序,把文件中的各记录依次排列起来,可使一个无序文件变成有序文件的一种操作。有
3、一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法插入排序法。插入排序包括:直接插入排序,折半插入排序,2-路插入排序,表插入排序,希尔排序。关键词:直接插入排序法;2路插入排序法;希尔排序法;MFC工程1 需求分析(1)有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法插入排序法。插入排序包括:直接插入排序,折半插入排序,2-路插入排序,表插入排序,希尔排序。(2)插入排序的基本思想是:在一个已排好序的记录子集的基础上,每一步将下一
4、个待排序的记录有序地插入到已排好序的记录子集中,知道将所有待排记录全部插入为止。这很像打扑克牌时,没抓一张牌,插入到合适位置,知道抓完牌为止,即可得到一个有序序列。(3) 直接插入排序:将一个记录插入到已排序好的有序表中,从而得到一个新的、记录数增1的有序表。设整个排序有n个数,则进行n-1趟插入,即:先将序列中的第1个记录看成是一个有序的子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减有序列为止。(4)2-路插入排序是在折半插入排序的基础上的发展。其目的是减少排序过程中记录移动的次数,但为此需n个记录的辅助空间。具体做法是:另设一个和L. r 同类型的数组d,首先将L.
5、 r 1赋值给d1,将 d1看成是排好序的序列中处于中间位置的记录,然后从L. r中第2个记录起依次插入到 d1之前或之后的有序序列中。先将待排序记录的关键字和 d1的关键字比较,若 L.ri.key d1 .key ,则将L.ri插入到 d1之前的有序表中。反之,将L.ri插入到 d1之后的有序表中。在实现算法时,将d 看成一个循环向量,并设两个指针first 和final分别指示排序过程中得到的有序序列中的第一个记录和最后一个记录在d中的位置。(5)希尔排序又称“缩小增量排序”,它属于插入排序类。它的基本思想是:先将整个待排序的记录分割成若干子序列分别进行“直接插入排序”,待整个序列中的记
6、录”基本有序“时,再对全体记录进行一次直接插入排序。2 算法基本原理(1)直接插入排序算法:排序过程为:将一个记录插入到已排序好的有序表中,从而得到一个新的、记录数增1的有序表。设整个排序有n个数,则进行n-1趟插入,即:先将序列中的第1个记录看成是一个有序的子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减有序列为止。直接插入排序过程如图2.1所示:(2)2-路插入排序算法:排序过程为:另设一个和L. r 同类型的数组d,首先将L. r 1赋值给d1,将 d1看成是排好序的序列中处于中间位置的记录,然后从L. r中第2个记录起依次插入到 d1之前或之后的有序序列中。先将待
7、排序记录的关键字和 d1的关键字比较,若 L.ri.key d1 .key ,则将L.ri插入到 d1之前的有序表中。反之,将L.ri插入到 d1之后的有序表中。在实现算法时,将d 看成一个循环向量,并设两个指针first 和final分别指示排序过程中得到的有序序列中的第一个记录和最后一个记录在d中的位置。 2-路插入排序过程如图2.2所示:(3)希尔排序算法: (3)希尔排序算法: (3)希尔排序算法:基本思想是:先将整个待排序的记录分割成若干子序列分别进行“直接插入排序”,待整个序列中的记录”基本有序“时,再对全体记录进行一次直接插入排序。希尔排序过程如下图2.3:初始关键字: 49 3
8、8 65 97 76 13 27 49 55 04 13 27 49 55 04 49 38 65 97 76 图2.3 希尔排序过程图3 类设计从上面的过程分析可以看到,本设计的关键所在是对所输入数据分别进行三种不同的排序,所输入的数据有两种类型,分别为int型和char型。对于两种不同的数据类型,可以先建立一个类模板,虚拟类型名为Type型,类模板名为Sort。在主函数main()中建立两个对象,分别制定对象类型为int型和char型。在虚拟类中声明各成员函数:void write()读入数组函数;void InsertionSort()直接插入排序函数;void Srsort(Type
9、mi)二路排序;void ShellSort(Type da,int k)void Shellinsert(Type dk)希尔排序。Void print()输出排序结果函数。分别在类模板外声明各成员函数。4 基于控制台的应用程序整个程序三部分。首先是声明类模板,其中包括输入输出数据成员函数的声明以及直接插入排序,2路排序,希尔排序的成员函数声明。其次是在类外对所有成员函数进行定义。最后在主函数中实现数据的排序操作。4.1 类的接口设计 #include#include#include#include#define num 50template /声明一个模板,虚拟类型名为Typeclass
10、Sort /类模板名为Sort private: int len; public: void write(); /声明读入数组函数 void InsertionSort(); /声明直接插入排序函数 void Srsort(Type mi); /声明2-路插入排序函数 void ShellSort(Type da,int t); void Shellinsert(Type dk); /声明希尔排序函数 void print(); /声明输出结果函数 Type arraynum; ;Template的意思是“模板”,是声明类模板时必须写的关键字。在template后面的尖括号内的内容为累的参数列
11、表,关键字class表示其后面的是类型参数。在本程序中Type就是一个类型参数名,它只是一个虚拟类型参数名,在之后的主函数中将被实际的类型名取代。4.2 类的实现template /直接插入排序 void Sort:InsertionSort() int i,j; for(i=2;i=len;+i) if(arrayiarrayi-1) array0=arrayi; for(j=i-1;array0arrayj;-j) arrayj+1=arrayj; arrayj+1=array0; template /2-路插入排序void Sort:Srsort(Type mi) int i,j; Ty
12、pe m,first,final,low,high; Type d100; d1=array1; first=1;final=1;m=1; for(i=2;i=len;+i) m=(first+final)/2; if(arrayidm) low=first;high=m-1; else low=m;high=final; while(low=high) /查找插入位置 m=(low+high)/2; if(arrayidm) m+; for(j=final+1;jm;j-) dj=dj-1; dm=arrayi; final+; j=first; for(i=1;i=len;+i) arra
13、yi=dj;+j; template /希尔排序void Sort:Shellinsert(Type dk) int i,j; for(i=dk+1;i=len;+i) if(arrayi0&(array0arrayj);j-=dk) arrayj+dk=arrayj; arrayj+dk=array0; templatevoid Sort:ShellSort(Type da,int t) int k; k=len/2; while(k) Shellinsert(k); k=k=2?1:k/2; template /读入数组void Sort:write() int i,l;printf(请输
14、入数组长度:); scanf(%d,&l); len=l; printf(请输入数组元素:n); for(i=1;iarrayi;template /显示结果void Sort:print() int i; printf(排序后的数组为:n); for(i=1;i=len;i+) coutarrayi ; coutendl;在类模板外定义成员函数时,应写成类模板形式。不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式储存,即都不占用对象的存储空间。一个对象所占的空间大小只取决于该对象中数据成员所占的空间,而与成员函数无关。函数代码是存储在对象空间之外的。4.3 主函数设计vo
15、id main() int i,j; Sort s; Sort p; couti; if(i=j) s.write(); couti; switch(i) case 1:s.InsertionSort();break; case 2:s.Srsort(s.array);break; case 3:s.ShellSort(s.array,3);break; default:break; s.print(); else p.write(); couti; switch(i) case 1:p.InsertionSort();break; case 2:p.Srsort(p.array);break
16、; case 3:p.ShellSort(p.array,3);break; default:break; p.print(); 在程序的主函数部分,建立了两个实际的类对象s和p,实际类型参数分别为int型和char型。首先通过选择参数类型来调用读入数组函数,进行数据的输入。其次选择排序类型,根据所选的类型调用相应的排序函数进行排序。最后通过输出函数输出排序之后的数据,完成整个程序的编译。4.4 基于控制台的应用程序测试程序运行结果如图4.1所示。 图4.1 数组长度为10的int型数据直接插入排序图 上述结果所应用的排序方法是直接插入排序,接下来下图4.2,图4.3是分别运用2-路插入排序和
17、希尔排序的结果。 图4.2 数据长度为10的char型数据2-路插入排序图 图4.3 数组长度为8的int型数据希尔排序图从上述三个图中很容易看出三种排序方法程序运行的正确性。无论是int型还是char型都能通过所选的排序方法进行正确的排序。5 基于MFC的应用程序MFC是一个界面开发系统,它提供的类绝大部分界面开发,关联一个窗口的动作。MFC是WindowsAPI的封装,大大简化了我们的工作。DOS界面程序采用字符交互式实现数据输入输出,主要通过cin,cout等I/O流实现,而MFC的图形程序界面采用标准Windows窗口和控件实现输入输出,因此必须在MFC类的框架下加入上面所设计的排序算
18、法程序,并通过图形界面的输入输出改造来完成。5.1 基于MFC的应用程序设计5.1.1 MFC程序界面设计首先在VC中建立MFC AppWizard(exe)工程,名称为PaixuMFC,并在向导的Step1中选择基本对话框,即建立基于对话框的应用程序,如下图5.1,图5.2所示。 图5.1 建立MFC AppWizard(exe)工程,名称为PaixuMFC 图5.2 建立基于对话框的应用程序将对话框资源中的默认对话框利用工具箱改造成如下界面,如图5.3所示。 图5.3 利用工具箱建立基本界面图5.3所示的界面中包含了3个Static Text控件,3个Button控件,和10个Edit B
19、ox控件,控件的基本信息列表如下表5.1所示。 表5.1 控件的基本信息控件类别控件ID控件Caption说明Static TextIDC_STATIC课程设计-插入排序输入数组数据输出排序结果BottonIDC_BUTTON1直接插入排序IDC_BUTTON22-路插入排序IDC_BUTTON3希尔排序Edit BoxIDC_EDIT1 IDC_EDIT5输入的五个数据IDC_EDIT6 IDC_EDIT10输出排序之后的五个数据5.1.2 MFC程序代码设计为了能够将对话框界面上的控件能够与代码联系起来,需要为10个Edit Box控件建立Member Variables,按Ctrl+w键
20、进入MFC ClassWizard界面,选择Member Variables选项卡,可显示成员变量设置界面,如图5.4所示 图5.4 设置成员变量通过该界面设置与10个Edit Box控件对应的成员变量,具体如表5.2所示。 表5.2 控件基本信息控件ID成员变量类型成员变量名称IDC_EDIT1 IDC_EDIT5intm_w1m_w5IDC_EDIT6 IDC_EDIT10intm_w6m_10下面是编写代码的重要阶段,可以借鉴在设计基于DOS界面的控制台应用程序的代码,并将其作必要的改写,具体内容如下。编写直接插入排序按钮的消息处理函数,实现数据排序,具体代码如下:void CPaixu
21、MFCDlg:OnButton1() int a10; int len=5; int i,j; UpdateData(true); a1=m_w1; a2=m_w2; a3=m_w3; a4=m_w4; a5=m_w5; for(i=2;i=len;+i) if(aiai-1) a0=ai; for(j=i-1;a0aj;-j) aj+1=aj; aj+1=a0; for(i=0;i=len;i+) printf(%d,ai); m_w6=a1; m_w7=a2; m_w8=a3; m_w9=a4; m_w10=a5; UpdateData(false); 编写2-路插入排序按钮的消息处理函数
22、,实现数据排序,具体代码如下:void CPaixuMFCDlg:OnButton2() int a10; int len=5; int i,j; UpdateData(true); a1=m_w1; a2=m_w2; a3=m_w3; a4=m_w4; a5=m_w5; int low,high; int d100; d1=a1; int first=1;int final=1;int m=1; for(i=2;i=len;+i) m=(first+final)/2; if(aidm) low=first;high=m-1; else low=m;high=final; while(low=
23、high) m=(low+high)/2; if(aidm) m+; for(j=final+1;jm;j-) dj=dj-1; dm=ai; final+; j=first; for(i=1;i=len;+i) ai=dj;+j; for(i=1;i=len;i+)printf(%d,ai); m_w6=a1; m_w7=a2; m_w8=a3; m_w9=a4; m_w10=a5; UpdateData(false); 编写希尔排序按钮的消息处理函数,实现数据排序,具体代码如下:void CPaixuMFCDlg:OnButton3() int a10; int len=5; int i,
24、j; UpdateData(true); a1=m_w1; a2=m_w2; a3=m_w3; a4=m_w4; a5=m_w5; int k=len/2; while(k) for(i=k+1;i=len;+i) if(ai0&(a0aj);j-=k) aj+k=aj; aj+k=a0; k=k=2?1:k/2; for(i=1;i=len;i+) printf(%d,ai);m_w6=a1;m_w7=a2; m_w8=a3; m_w9=a4; m_w10=a5;UpdateData(false); 5.2基于MFC的应用程序测试运行程序后,首先出现的界面如图5.5所示。 图5.5 程序运行
25、界面然后再输入数据如图5.6 图5.6 输入排序数据 单击直接插入排序按钮,实现排序并将排序结果显示出来,如图5.7所示。 图5.7 显示直接插入排序结果 第二次输入数据,单击希尔排序按钮,实现排序并将排序结果显示出来,如图5.8所示。 图5.8 希尔排序结果图 图5.9 直接插入排序结果图单击确定或取消按钮后,程序能够正常实现退出。 由于是初次进行MFC方面的设计,所以在程序实现过程中遇到了不少问题,比如在希尔排序过程中利用到了函数的调用,这一点在刚开始时连续出错,但是最终还是解决了问题,成功运行了程序,实现了三种插入排序。通过这次课程设计,对MFC相关的只是也掌握了不少。结 论 程序的关键
26、在于建立一个虚拟类模板,然后再类模板中声明各成员函数,这些成员函数在类模板外进行定义,这里要特别注意在类模板外定义成员函数的方法。除了类模板的基本特征之外,结合问题的实际需要,三种排序方法的算法要具备正确性,可读性,健壮性。在类模板外定义成员函数时,应写成类模板形式。不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式储存,即都不占用对象的存储空间。一个对象所占的空间大小只取决于该对象中数据成员所占的空间,而与成员函数无关。函数代码是存储在对象空间之外的。在程序的主函数部分,建立了两个实际的类对象s和p,实际类型参数分别为int型和char型。首先通过选择参数类型来调用读入数组函数,进行数据的输入。其次选择排序类型,根据所选的类型调用相应的排序函数进行排序。最后通过输出函数输出排序之后的数据,完成整个程序的编译。 程序的成功运行是一个艰辛的过程,如果只是实现一般的功能,将变得容易很多,当加上MFC,不论是效率还是程序可行性,都需要精心设计。这次做课程设计的过程中,学到了不少MFC的知识和排序的改进算法。因而以后必须要加强程序MFC方面的训练,这样才能在将编程思想和数据结构转换为代码的时候能得心应手。 自己编好程序上机
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1