北邮数据结构实验四数组排序.docx
- 文档编号:5654650
- 上传时间:2022-12-30
- 格式:DOCX
- 页数:32
- 大小:235.91KB
北邮数据结构实验四数组排序.docx
《北邮数据结构实验四数组排序.docx》由会员分享,可在线阅读,更多相关《北邮数据结构实验四数组排序.docx(32页珍藏版)》请在冰豆网上搜索。
北邮数据结构实验四数组排序
数据结构实验报告
实验名称:
实验四-数组排序
学生姓名:
班级:
班内序号:
学号:
日期:
2013年12月19日
1.实验要求
使用简单数组实现下面各种排序算法,并进行比较。
排序算法:
1、插入排序
2、希尔排序
3、冒泡排序
4、快速排序
5、简单选择排序
6、堆排序(选作)
7、归并排序(选作)
8、基数排序(选作)
9、其他
要求:
1、测试数据分成三类:
正序、逆序、随机数据
2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。
3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)
4、对2和3的结果进行分析,验证上述各种算法的时间复杂度
编写测试main()函数测试线性表的正确性。
2.程序分析
2.1存储结构
数组:
例如:
1436495280
5861239775
2.2关键算法分析
1、直接插入排序Insert():
voidInsertSort(intr[],intn)//直接插入排序
{
intcount1=0,count2=0;//分别用来记录插入排序比较和移动次数的计数器
for(inti=2;i<=n-1;i++)
{
if(r[i] { r[0]=r[i];//设置哨兵 count2++; intj; for(j=i-1;count1++,r[0] { r[j+1]=r[j];//元素后移 count2++; } r[j+1]=r[0];//插入记录 count2++; } elsecount1++;//此时虽然没有移动,但是已经进行了一次比较 } for(intk=1;k cout< cout< cout<<"比较次数为"< } 直接插入排序的基本思想便是每将一个待排序的元素按其关键码的大小插入到一个已经排序好的有序序列中,直到全部元素都排好。 而我认为直接插入排序的程序中很关键的一点便是加入了监视哨兵,这时的程序的执行中不仅减少了空间的使用也节省了程序执行的时间。 2、希尔排序ShellSort(): voidShellSort(intr[],intn)//希尔排序 { inti,d,j; intcount1=0,count2=0; for(d=n/2;d>=1;d=d/2)//以增量为d进行直接插入排序 { for(i=d+1;i { r[0]=r[i];//暂存被插入记录 for(j=i-d;j>0&&r[0] r[j+d]=r[j];//记录后移d个位置 r[j+d]=r[0]; count1++; count2=count2+d;//每次都移动d个位置 } count1++; } for(i=1;i cout< cout< cout<<"比较次数为"< } 希尔排序而基本思想便是将带排序的元素及分成多个子集,分别对这些子集进行直接直接插入排序,带到真个程序基本有序时在对元素进行一次直接插入排序。 而为了使集合基本有序而不是局部有序,不能简单地逐段分割,而是将相距某个增量的元素组成一个子序列,这个增量逐步缩小,最后等于1,这样最终的结果就是整个序列有序。 3、起泡排序BubbleSort(): voidBubbleSort(intr[],intn)//起泡排序 { inttemp,pos,bound; intcount1=0,count2=0; pos=n-1;//第一趟起泡排序的范围是r[1]到r[n] while(pos! =0)//仅当上一趟排序有记录交换才进行本趟排序 { bound=pos;//本次无序元素的范围 pos=0;//控制外循环结束 for(intj=1;j { count1++;//接下来有一次比较 if(r[j]>r[j+1])//相邻元素比较 { temp=r[j];//交换r[j]和r[j+1] r[j]=r[j+1]; r[j+1]=temp; pos=j;//记录每一次发生记录交换的位置,当j=0时说明一次比较也没有了,即已经全部有序了 count2=count2+3;//一个交换语句为一次移动,共移动了次 } } } for(inti=1;i cout< cout< cout<<"比较次数为"< } 起泡排序的基本思想是两两比较相邻的元素,如果反序则交换位置,直到没有反序的元素为止。 由于基本的起泡排序算法每次只能添加一个元素到有序区,所以存在无序区的有序元素也需要比较的问题,为了去掉这种不必要的开销,可以将最后一次比较的位置pos作为下一趟无序区的末尾。 4、快速排序: intPartition(intr[],intfirst,intend,int&count1,int&count2)//快速排序一次划分 { inti=first;//初始化 intj=end; inttemp; while(i { while(i { j--;//右侧扫描 count1++; } if(i { temp=r[i]; r[i]=r[j];//将较小记录交换到前面 r[j]=temp; i++; count2=count2+3; count1++; } while(i { i++;//左侧扫描 count1++; } if(i { temp=r[i]; r[i]=r[j];//将较小记录交换到前面 r[j]=temp;//将较大记录交换到后面 j--; count2=count2+3; count1++; } } returni;//i为轴值记录的最终位置 } voidQuickSort(intr[],intfirst,intend,int&count1,int&count2)//快速排序 { if(first {//递归结束,继续执行下边的操作 intpivot=Partition(r,first,end,count1,count2);//一次划分 QuickSort(r,first,pivot-1,count1,count2);//递归地对左侧子序列进行快速排序 QuickSort(r,pivot+1,end,count1,count2);//递归地对右侧子序列进行快速排序 } } 快速排序的基本思想便是在分区中选一个元素作为轴值,将待排序元素划分为两个分区,使得左侧关键码均小于或等于轴值,右侧的关键码均大于或等于轴值,然后对着两个分区重复上述排序过程,直到整个序列有序。 5、简单选择排序SelectSort(): voidSelectSort(intr[],intn)//简单选择排序 { inti; intj; intindex;//初始化 inttemp; intcount1=0,count2=0; for(i=1;i { index=i;//假设index是最小的 for(j=i+1;j { if(r[j] index=j;//赋值给index count1++;//比较次数加一 } //count1++;//在判断不满足循环条件j if(index! =i) { temp=r[i];//将无序区的最小记录与第i个位置上的记录交换 r[i]=r[index]; r[index]=temp; count2=count2+3;//移动次数加 } } for(i=1;i cout< cout< cout<<"比较次数为"< } 简单选择排序的基本思想是在每一趟的排序区中选出最小的元素换到前边,重复不断的执行,直到元素全部排序完为止。 6、堆排序: voidSift(intr[],intk,intm,int&count1,int&count2)//筛选法调整堆,s,t分别为比较和移动次数,m为编号最大的叶子结点的编号 { inti=k; intj=2*i+1;//置i为要筛的结点,j为i的左孩子 inttemp; while(j<=m)//筛选还没有进行到叶子 { if(j j++;//比较i的左右孩子,j为较大者 count1=count1+2;//该语句之前和之后分别有一次比较 if(r[i]>r[j]) break;//根结点已经大于左右孩子中的较大者则结束循环 else { temp=r[i]; r[i]=r[j]; r[j]=temp;//将根结点与结点j交换 i=j; j=2*i+1;//下一个被筛结点位于原来结点j的位置 count2=count2+3;//移动次数加 } } } voidHeapSort(intr[],intn)//堆排序 { intcount1=0,count2=0;//计数器,计比较和移动次数 inti; inttemp; for(i=n/2;i>=0;i--)//初始建堆,从下向上(从最后一个分支结点开始)的过程(整体) Sift(r,i,n,count1,count2); for(i=n-1;i>0;i--)//重复执行移走堆顶及重建堆的操作 { temp=r[i];//将堆顶元素与将堆顶记录和当前未经排序子序列r[1..i]中最后一个记录相互交换 r[i]=r[0]; r[0]=temp;//完成一趟排序,输出记录的次序状态 Sift(r,0,i-1,count1,count2);//重建堆 } for(i=1;i cout< cout< cout<<"比较次数为"< } 堆排序是在简单选择排序的基础上进行了改进,即利用了前一趟比较后的结果,减少比较次数,从而提高了整个排序的效率。 而此次的对用的是大根堆。 7、归并排序: voidMerge(intr[],intr1[],ints,intm,intt)//一次归并 { inti=s;//i指向r[s-m] intj=m+1;//j指向r[m+1-t] intk=s;//k指向r1 while(i<=m&&j<=t) { if(r[i]<=r[j]) r1[k++]=r[i++];//取r[i]和r[j]中较小者放入r1[k],并且自加 else r1[k++]=r[j++]; } if(i<=m) while(i<=m)//若第一个子序列r[s-m]没处理完,则进行收尾处理 r1[k++]=r[i++]; else while(j<=t)//若第二个子序列r[m+1-t]没处理完,则进行收尾处理 r1[k++]=r[j++]; } voidMergePass(intr[],intr1[],intn,inth)//一趟归并 { inti=0; intk; while(i<=n-2*h)//待归并记录至少有两个长度为h的子序列 { Merge(r,r1,i,i+h-1,i+2*h-1); i+=2*h;//跳到下一个子序列进行比较排序 } if(i Merge(r,r1,i,i+h-1,n);//待归并序列中有一个长度小于h elsefor(k=i;k<=n;k++)//待归并序列中只剩一个子序列 r1[k]=r[k]; } voidMergeSort(intr[],intr1[],intn)//归并排序 { inth=1; inti; while(h { MergePass(r,r1,n-1,h);//归并 h=2*h; MergePass(r1,r,n-1,h); h=2*h; } for(i=1;i cout< cout< } 此处的归并排序违规并排序中最简单的二路归并排序,即先将n个元素的序列分为n个子序列,再按二倍的关系一一合成一个新的完整的序列。 将两个有序序列合成一个完整序列的方法是逐一对两个序列中的元素进行比较,并把较小者放入缓冲区,然后取出较小者所在的序列的下一个元素进行比较,往复执行,知道其中一个序列的元素全部放入缓冲区,再把另一个序列中的剩下的元素放在缓冲区的尾部。 8、主函数: voidNewarray(inta[],intb[],intc[])//产生顺序、逆序及随机数组 { cout<<"新随机数组: "; c[0]=0; a[0]=0; b[0]=0; for(ints=1;s<11;s++) { a[s]=s; b[s]=20-s; c[s]=rand()%50+1; cout< } cout< } voidmain() { srand(time(NULL)); constintnum=11;//赋值,最大的数组的容量 inta[num]; intb[num]; intc[num]; intc1[num]; c[0]=0; a[0]=0; b[0]=0; Newarray(a,b,c); cout<<"顺序数组: ";
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 实验 数组 排序