排序课程设计报告C++.docx
《排序课程设计报告C++.docx》由会员分享,可在线阅读,更多相关《排序课程设计报告C++.docx(37页珍藏版)》请在冰豆网上搜索。
排序课程设计报告C++
一需求分析
1.运行环境
MicrosoftVisualStudio2005
2.程序所实现的功能
对直接插入排序、折半插入排序、冒泡排序、简单选择排序、快速排序、堆排序、归并排序算法的演示,并且输出每一趟的排序情况。
3.程序的输入(包含输入的数据格式和说明)
<1>排序种类三输入
<2>排序数的个数的输入
<3>所需排序的所有数的输入
4.程序的输出(程序输出的形式)
<1>主菜单的输出
<2>每一趟排序的输出,即排序过程的输出
二设计说明
1.算法设计思想
<1>交换排序(冒泡排序、快速排序)
交换排序的基本思想是:
对排序表中的数据元素按关键字进行两两比较,如果发生逆序(即排列顺序与排序后的次序正好相反),则两者交换位置,直到所有数据元素都排好序为止。
<2>插入排序(直接插入排序、折半插入排序)
插入排序的基本思想是:
每一次设法把一个数据元素插入到已经排序的部分序列的合适位置,使得插入后的序列仍然是有序的。
开始时建立一个初始的有序序列,它只包含一个数据元素。
然后,从这个初始序列出发不断插入数据元素,直到最后一个数据元素插到有序序列后,整个排序工作就完成了。
<3>选择排序(简单选择排序、堆排序)
选择排序的基本思想是:
第一趟在有n个数据元素的排序表中选出关键字最小的数据元素,然后在剩下的n-1个数据元素中再选出关键字最小(整个数据表中次小)的数据元素,依次重复,每一趟(例如第i趟,i=1,…,n-1)总是在当前剩下的n-i+1个待排序数据元素中选出关键字最小的数据元素,作为有序数据元素序列的第i个数据元素。
等到第n-1趟选择结束,待排序数据元素仅剩下一个时就不用再选了,按选出的先后次序所得到的数据元素序列即为有序序列,排序即告完成。
<4>归并排序(两路归并排序)
两路归并排序的基本思想是:
假设初始排序表有n个数据元素,首先把它看成是长度为1的首尾相接的n个有序子表(以后称它们为归并项),先做两两归并,得n/2上取整个长度为2的归并项(如果n为奇数,则最后一个归并项的长度为1);再做两两归并,……,如此重复,最后得到一个长度为n的有序序列。
2.程序的主要流程图
3.程序的主要模块(要求对主要流程图中出现的模块进行说明)
程序的主要模块主要分为主菜单模块和排序算法演示模块。
<1>主菜单
主要功能:
程序运行时,可使运行者根据提醒输入相关操作,从而进入不同的排序方法或者退出。
<2>排序方法及输出
根据运行者对排序的不同选择,进入排序过程
a.直接插入排序:
根据直接排序的算法,输出排序过程
b.折半插入排序:
根据折半插入的算法,输出排序过程
c.冒泡排序:
根据冒泡排序算法,输出排序过程
d.简单选择排序:
根据简单选择排序的算法,输出排序过程
e.快速排序:
根据快速排序的算法,输出排序过程
f.堆排序:
根据堆排序的算法,输出排序过程
g.归并排序:
根据归并排序的算法,输出排序过程
4.程序的主要函数及其伪代码说明
<1>模板类
主要说明程序中用到的类的定义
templateclasssortlist
{
private:
intcurrentsize;//数据表中数据元素的个数
public:
type*arr;//存储数据元素的向量(排序表)
sortlist():
currentsize(0){arr=newtype[maxsize];}//构造函数
sortlist(intn){arr=newtype[maxsize];currentsize=n;}
voidinsert(inti,typex){arr[i]=x;}
~sortlist(){delete[]arr;}//析构函数
voidswap(type&x,type&y)//数据元素x和y交换位置
{typetemp=x;x=y;y=temp;}
voidbubblesort();//冒泡排序
voidquicksort(intlow,inthigh);//快速排序
voidinsertionsort();//直接插入排序
voidbinaryinsertsort();//折半插入排序
voidselectsort();//简单选择排序
voidheapsort();//堆排序
voidmergesort(sortlist&table);//归并排序
voidfilterdown(constintstart);//建立最大堆
voidmergepass(sortlist&sourcetable,sortlist&mergedtable,constintlen);//一趟归并
voidmerge(sortlist&sourcetable,sortlist&mergedtable,constintleft,constintmid,constintright);//两路归并算法
};
<2>直接插入排序
直接插入排序的基本思想:
开始时把第一个数据元素作为初始的有序序列,然后从第二个数据元素开始依次把数据元素按关键字大小插入到已排序的部分排序表的适当位置。
当插入第i(1
如此进行n-1次插入,就完成了排序。
以下是在顺序表上实现的直接插入排序
在顺序表上进行直接插入排序时,当插入第i(1
伪代码如下
template//直接插入排序
voidsortlist:
:
insertionsort()
{
typetemp;
intj;
for(inti=1;i<=currentsize-1;i++)
{
temp=arr[i];j=i-1;
while(j>=0&&temp{arr[j+1]=arr[j];j--;}
arr[j+1]=temp;
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
num=0;
}
<3>折半插入排序
折半插入排序的基本思想:
设在排序表中有n个数据元素arr[0],arr[1],…,arr[n-1]。
其中,arr[0],arr[1],…,arr[n-1]是已经排好序的部分数据元素序列,在插入arr[i]时,利用折半查找方法寻找arr[i]的插入位置。
折半插入排序方法只能在顺序表存储结构实现。
伪代码如下:
template//折半插入排序
voidsortlist:
:
binaryinsertsort()
{
typetemp;
intleft,right;
for(inti=1;i{
left=0;right=i-1;temp=arr[i];
while(left<=right)//找插入位置
{
intmid=(left+right)/2;
if(tempelseleft=mid+1;
}
for(intk=i-1;k>=left;k--)//向后移动
arr[k+1]=arr[k];
arr[left]=temp;
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
num=0;
}
<4>冒泡排序
冒泡排序的基本思想是:
设排序表中有n个数据元素。
首先对排序表中第一,二个数据元素的关键字arr[0]和arr[1]进行比较。
如果前者大于后者,则进行交换;然后对第二,三个数据做同样的处理;重复此过程直到处理完最后两个相邻的数据元素。
我们称之为一趟冒泡,它将关键字最大的元素移到排序表的最后一个位置,其他数据元素一般也都向排序的最终位置移动。
然后进行第二趟排序,对排序表中前n-1个元素进行与上述同样的操作,其结果使整个排序表中关键字次大的数据元素被移到arr[n-2]的位置。
如此最多做n-1趟冒泡就能把所有数据元素排好序。
伪代码如下:
template//冒泡排序
voidsortlist:
:
bubblesort()
{
inti=1;
intfinish=0;//0表示还没有排好序
while(ifinish)
{
finish=1;//排序结束标志置为,假定已经排好序
for(intj=0;jif(arr[j]>arr[j+1])//逆序
{
swap(arr[j],arr[j+1]);//相邻元素交换位置
finish=0;
}//排序结束标志置为,表示本趟发生了交换,说明还没有排好序
i++;
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
num=0;
}
<5>简单选择排序(直接选择排序)
直接选择排序的算法基本思想是:
a)开始时设i的初始值为0。
b)如果ic)若arr[k]不是这组数据元素中的第一个数据元素(i≠k),则将arr[k]与arr[i]这两数据元素的位置对调;
d)令i=i+1转步骤b)。
伪代码如下:
template
voidsortlist:
:
selectsort()//简单选择排序
{
intk;
for(inti=0;i<=currentsize-1;i++)
{
k=i;
for(intj=i+1;jif(arr[j]k=j;//k指示当前序列中最小者的位置
if(k!
=i)//最小关键字的数据元素位置不等于i
swap(arr[i],arr[k]);
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
num=0;
}
<6>快速排序
快速排序(QuickSort)又被称做分区交换排序,这是一种平均性能非常好的排序方法。
其算法基本思想是:
任取排序表中的某个数据元素(例如取第一个数据元素)作为基准,按照该数据元素的关键字大小,将整个排序表划分为左右两个子表:
左侧子表中所有数据元素的关键字都小于基准数据元素的关键字。
右侧子表中所有数据元素的关键字都大于或等于基准数据元素的关键字,基准数据元素则排在这两个子表中间(这也是该数据元素最终应安放的位置),然后分别对这两个子表重复施行上述方法的快速排序,直到所有的子表长度为1,则排序结束。
伪代码如下:
template//快速排序
voidsortlist:
:
quicksort(intlow,inthigh)//在待排序区间[low,high]上,递归地进行快速排序
{
inti=low,j=high;
typetemp=arr[low];//取区间第一个位置为基准位置
if(i{
while(i{
while(iif(iwhile(i=arr[i])i++;
if(i}
arr[i]=temp;//将基准元素就位
cout<<"第"<<++x<<"趟排序结果为:
";
for(intt=0;tcout<cout<quicksort(low,i-1);//在左子区间递归进行快速排序
quicksort(i+1,high);//在右子区间递归进行快速排序
}
}
<7>堆排序(包括建立最大堆和堆排序两个过程)
堆排序算法的基本思想是:
a.对排序表中的数据元素,利用堆的调整算法形成初始堆。
b.输出堆顶元素。
c.对剩余元素重新调整形成堆。
d.重复执行第b、c步,直到所有数据元素被输出。
(1)建立最大堆的伪代码如下:
template//建立最大堆
voidsortlist:
:
filterdown(constintstart)
{//向下调整使从start开始到currentsize-1为止的子表成为最大堆
inti=start,j=2*i+1;//j为i的左孩子
inttablesize=currentsize;
typetemp=arr[i];
while(j<=currentsize-1)
{
if(jj++;//在两个孩子中选关键字较大者
if(temp>=arr[j])break;
else{arr[i]=arr[j];i=j;j=2*j+1;
}
}
arr[i]=temp;
}
(2)堆排序
如果建立的堆满足最大堆的条件,则堆的第一个数据元素arr[0]具有最大的关键字,将arr[0]与arr[n-1]对调,把具有最大关键字的数据元素交换到最后,再对前面的n-1个数据元素使用堆的调整算法,重新建立最大堆,结果把具有次最大关键字的数据元素又上浮到堆顶,即arr[0]的位置,再对调arr[0]和arr[n-2],…,如此反复执行n-1次,最后得到全部排序好的数据元素序列。
伪代码如下:
template//堆排序
voidsortlist:
:
heapsort()
{
inttablesize=currentsize;
for(inti=(currentsize-2)/2;i>=0;i--)
filterdown(i);//初始建堆
for(inti=currentsize-1;i>=1;i--)
{
swap(arr[0],arr[i]);//堆顶元素和最后一个元素交换
currentsize--;
filterdown(0);//重建最大堆
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
num=0;
currentsize=tablesize;
}
<8>归并排序(包括归并算法,一趟归并算法和归并排序)
1 归并算法
其基本思想是:
设有两个有序表A和B,其数据元素个数(表长)分别为n和m,变量i和j分别是表A和表B的当前检测指针;设表C是归并后的新有序表,变量k是它的当前存放指针。
开始时i、j、k都分别指向A、B、C三个表的起始位置;然后根据A[i]与B[j]的关键字的大小,把关键字小的数据元素放到新表C[k]中;且相应的检测指针(i或j)和存放指针k增加1.如此循环,当i与j中有一个已经超出表长时,将另一个表中的剩余部分照抄到新表C[k]~C[m+n]中。
下面的归并算法中,两个待归并的有序表首尾相接存放在数组sourcetable.arr[]中,其中第一个表的下标范围从left到mid,另一个表的下标范围从mid+1到right。
前一个表中有mid-left+1个数据元素,后一个表中有right–mid个数据元素。
归并后得到的新有序表有right–mid个数据元素。
归并后得到的新有序表存放在另一个辅助数组mergedtable.arr[]中,其下标范围从left到right。
伪代码如下:
template
voidsortlist:
:
merge(sortlist&sourcetable,sortlist&mergedtable,constintleft,constintmid,constintright)
{
inti=left,j=mid+1,k=left;//指针初始化
//i是前一段的当前元素位置,j是后一段的当前元素位置,k是辅助数组的当前位置
while(i<=mid&&j<=right)
if(sourcetable.arr[i]<=sourcetable.arr[j])
{mergedtable.arr[k]=sourcetable.arr[i];i++;k++;}
else{mergedtable.arr[k]=sourcetable.arr[j];j++;k++;}
if(i<=mid)
for(intp=k,q=i;q<=mid;p++,q++)
mergedtable.arr[p]=sourcetable.arr[q];//把前一段复制到mergedtable
else
for(intp=k,q=j;q<=right;p++,q++)
mergedtable.arr[p]=sourcetable.arr[q];//把后一段复制到mergedtable
}
2 一趟归并算法
设数组sourcetable.arr[0]到sourcetable.arr[n-1]中的n个数据元素已经分为一些长度为len的归并项,将这些归并项两两归并,归并成一些长度为2len的归并项,结果放到mergedtable.arr[]中。
如果n不是2len的整数倍,则一趟归并到最后,可能遇到两种情况:
剩下一个长度为len的归并项和一个长度不足len的归并项,可用一次merge算法,将它们归并成一个长度小于2len的归并项。
只剩下一个归并项,其长度小于或等于len,可将它直接复制到数组mergedtable.arr[]中。
伪代码如下:
template
template
voidsortlist:
:
mergepass(sortlist&sourcetable,sortlist&mergedtable,constintlen)
{
inti=0;
while(i+2*len<=currentsize-1)//表示至少有个子序列
{
merge(sourcetable,mergedtable,i,i+len-1,i+2*len-1);
i+=2*len;
}
if(i+len<=currentsize-1)//若只有最后两个子序列
merge(sourcetable,mergedtable,i,i+len-1,currentsize-1);
else//若只有最后一个子序列
for(intj=i;j<=currentsize-1;j++)
mergedtable.arr[j]=sourcetable.arr[j];
if(len<=currentsize-1)
{
if(num{
cout<<"第"<<++num<<"趟排序结果为:
";
for(intt=0;tcout<cout<}
}
}
3 归并排序
在一趟归并算法的基础上,实现两路归并排序算法。
在两路归并排序算法中,初始排序表存放在数组table.arr[]中,第一趟归并将table.arr[]中的归并项两两归并,结果存放在辅助数组temptable.arr[]中。
第二趟将temptable.arr[]中的归并项两两归并,结果放回原数组table.arr[]中,如此反复进行。
为了将最后归并结果仍放在数组table.arr[]中,归并趟数应为偶数。
如果做奇数趟就能完成时,最后还需要执行一次一趟归并过程,由于这时的归并项长度len>=n,因此在则趟归并中while循环不执行,只做把temptable.arr[]中的数据元素复制到table.arr[]的工作。
伪代码如下:
template
voidsortlist:
:
mergesort(sortlist&table)
{//按数据元素关键字非递减的顺序对排序表table中数据元素进行递归排序
sortlisttemptable;
intlen=1;
while(len{
mergepass(table,temptable,len);len*=2;
mergepass(temptable,table,len);len*=2;
}
num=0;
}
<9>主函数
主要功能是显示主菜单,以及对各种排序的调用
伪代码如下:
intmain()//主函数
{
cout<<"***********************************************************************"<cout<<"排序问题"<cout<<"**********************************************************