第十章内部排序_第1页
第十章内部排序_第2页
第十章内部排序_第3页
第十章内部排序_第4页
第十章内部排序_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第十章

内部排序

概述插入排序(直接插入、折半插入、表插入排序、希尔排序)交换排序(起泡排序、快速排序)选择排序(简单选择排序、树形选择排序、堆排序)归并排序

基数排序10.1概述排序:将一组杂乱无章的数据排列成一个按关键字有序的序列。

数据表(datalist):

它是待排序数据对象的有限集合。关键字(key):排序算法的稳定性:

如果在对象序列中有两个对象r[i]和r[j],它们的关键字k[i]==k[j],且在排序之前,对象r[i]排在r[j]前面。如果在排序之后,对象r[i]仍在对象r[j]的前面,则称这个排序方法是稳定的,否则称这个排序方法是不稳定的。内排序与外排序:

内排序是指在排序期间数据对象全部存放在内存的排序;外排序是指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。排序的时间开销:

排序的时间开销是衡量算法好坏的最重要的标志。排序的时间开销可用算法执行中的数据比较次数与数据移动次数来衡量。各节给出算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象关键字序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算。衡量排序方法的标准

排序时所需要的平均比较次数排序时所需要的平均移动排序时所需要的平均辅助存储空间待排序的记录序列的存储方式(P264)存放在地址连续的空间,类似于线性表的顺序存储。静态链表地址排序本章讨论的排序,采取第一种方式存储。设数据类型定义为#defineMAXSIZE20Typedef

intKeyTypetypedefstruct{

KeyTypekey;//关键字项

InfoTypeotherinfo;//其它数据项}

RedType;//记录类型typedefstruct{

RedTyper[MAXSIZE+1];

intlength;//顺序表长}SqList;//顺序表类型10.2插入排序(InsertSorting)插入排序的基本方法是:每步将一个待排序的对象,按其关键字大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。直接插入排序的基本思想是:当插入第i(i

1)个对象时,前面的V[1],V[2],…,v[i-1]已经排好序。用v[i]的关键字与v[i-1],v[i-2],…的关键字顺序进行比较,找到插入位置将v[i]插入,原来位置上之后的所有对象依次向后顺移。各趟排序结果21254925*1608123456123456

021254925*160825i=221254925*160849i=3123456

021254925*160821254925*1608i=521254925*1608i=6i=425*1608123456

0123456

0123456

0直接插入排序的算法(p265算法10.1)voidInsertSort(SqList&L){for(inti=2;i<=L.length;++i)

if(LT(L.r[i].key,L.r[i-1].key))

{L.r[0]=L.r[i];

//L.r[0]为监视哨

for(intj=i-1;LT(L.r[0].key,L.r[j].key);--j) L.r[j+1]=L.r[j];

//记录后移

L.r[j+1]=L.r[0];//插入到正确位置 }}21254925*1608012345完成算法分析若设待排序的对象个数为L.length=n,则该算法的主程序执行n-1趟。关键字比较次数和对象移动次数与对象关键字的初始排列有关。最好情况:排序前对象已经按关键字大小从小到大有序(正序),每趟只需与前面的有序对象序列的最后一个对象的关键字比较1次,不需移动对象,总的关键字比较次数为n-1。最坏情况:排序前对象按关键字从大到小有序排列(逆序)。比较次数移动次数

算法分析若待排序对象序列中出现各种可能排列的概率相同,在平均情况下的关键字比较次数和对象移动次数约为n2/4。因此,直接插入排序的时间复杂度为o(n2)。

一个记录的辅助存储空间监视哨直接插入排序是一种稳定的排序方法。10.2.3希尔排序(ShellSort)希尔排序方法又称为“缩小增量”排序。[基本思想]:先将整个待排对象序列按照一定间隔分割成为若干子序列,分别进行直接插入排序然后缩小间隔,对整个对象序列重复以上的划分子序列和分别排序工作,直到最后间隔为1,此时整个对象序列已“基本有序”,进行最后一次直接插入排序注意:子序列的构成不是简单地“逐段分割”,而是将相隔某个“增量”的记录组成一个子序列。21254925*16080123452125*i=10849gap=32516492516084925*0821252125*1621254925*160801234521i=20849gap=22516491625*0821254925*08162125*2521254925*160801234521i=308gap=125164925*开始时

gap(间隔值)的值较大,子序列中的对象较少,排序速度较快;随着排序进展,gap

值逐渐变小,子序列中对象个数逐渐变多,由于前面工作的基础,大多数对象已基本有序,所以排序速度仍然很快。希尔排序的算法

voidShellSort(SqList&L,intdlta[],intt){//按增量序列dlta[0..t-1]对顺序表作希尔排序

for(intk=0;k<t;++k){ ShellInsert(L,dlta[k]); }}例如:dlta[3]={5,3,1}//一趟希尔插入排序,按间隔dk划分子序列

voidShellInsert(SqList&L,intgap){

for(inti=dk+1;i<=L.length;++i){ if(LT(L.r[i].key,L.r[i-dk].key)){ L.r[0]=L.r[i]; for(intj=i-dk;j>0&&T(L.r[0].key,L.r[j].key);j-=dk)

L.r[j+dk]=L.r[j];

L.r[j+dk]=L.r[0]; } }}希尔排序是不稳定的排序。10.3交换排序(ExchangeSort)

[交换排序的基本思想]:两两比较待排序对象的关键字,如果发生逆序(即排列顺序与排序后的次序正好相反),则交换之,直到所有对象都排好序为止。起泡排序(BubbleSort)设待排序对象序列中的对象个数为n。最多作n-1趟排序。在第i

趟中顺次两两比较r[j-1].Key和r[j].Key,j=i,i+1,,n-i-1。如果发生逆序,则交换r[j-1]和r[j]。总的时间复杂度是O(n2)冒泡排序是稳定的排序。

起泡排序的算法voidBubbleSort(SqList&L){for(inti=L.length,change=TRUE;i>1&&change;--i)

{ change=FALSE; for(intj=1;j<i;++j) if(LT(L.r[j+1].key,L.r[j].key))

{ElemTypetemp=L.r[j]; L.r[j]=L.r[j+1]; L.r[j+1]=temp; change=TRUE;

}}}快速排序(QuickSort)[快速排序方法的基本思想]:

任取待排序对象序列中的某个对象(例如取第一个对象)作为枢轴(pivot),按照该对象的关键字大小,将整个对象序列划分为左右两个子序列:

左侧子序列中所有对象的关键字都小于或等于枢轴对象的关键字

右侧子序列中所有对象的关键字都大于枢轴对象的关键字枢轴对象则排在这两个子序列中间(这也是该对象最终应安放的位置)。然后分别对这两个子序列重复施行上述方法,直到所有的对象都排在相应位置上为止。算法描述

QuickSort(List){if(List的长度大于1){

将序列List划分为两个子序列

LeftList和RightList;

QuickSort(

LeftList);

QuickSort(

RightList

);

将两个子序列

LeftList和

RightList

合并为一个序列List;}}一趟快速排序的设计设指针low和high,初值分别为low和high,设枢轴记录的关键字为pivotkey,首先从high所指位置起向前搜索找到第一个关键字小于pivotkey的记录和枢轴记录交换然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录和枢轴记录交换重复,直到low=high。Low=high的位置就是枢轴记录的位置一趟快速排序的算法(P27410.6(a))intPartition(SqList&L,intlow,inthigh){

intpivotkey=L.r[low].key;while(low<high){ while(low<high&&L.r[high].key>=pivotkey)--high; L.r[low]<->L.r[high];

while(low<high&&L.r[low].key<=pivotkey)++low; L.r[high]<->L.r[low];}

returnlow;//返回枢轴位置}初始关键字4938659776132749ijj27386597761349

49进行1次交换后iiij进行2次交换后2738499776136549ijj进行3次交换后2738139776496549iji进行4次交换后2738134976976549ijjj完成一趟排序2738134976976549一趟快速排序的算法(P27410.6(b))intPartition(SqList&L,intlow,inthigh){L.r[0]=L.r[low];intpivotkey=L.r[low].key;while(low<high){ while(low<high&&L.r[high].key>=pivotkey)--high; L.r[low]=L.r[high];

while(low<high&&L.r[low].key<=pivotkey)++low; L.r[high]=L.r[low];}

L.r[low]=L.r[0];//枢轴记录到位

returnlow;//返回枢轴位置}快速排序的算法

voidQSort(SqList&L,intlow,inthigh){ if(low<high){ intpivotloc=Partition(L,low,high); QSort(L,low,

pivotloc-1);

QSort(L,pivotloc+1,high);}}voidQuickSort(SqList&L){ QSort(L,1,L.length);}可以证明,函数quicksort的平均计算时间是o(nlog2n)。实验结果表明:就平均计算时间而言,快速排序是我们所讨论的所有内排序方法中最好的一个。

快速排序是递归的,需要有一个栈存放每层递归调用时的指针和参数。要求存储开销为o(log2n)。快速排序是一种不稳定的排序方法。对于n较大的平均情况而言,快速排序是“快速”的,但是当n很小时,这种排序方法往往比其它简单排序方法还要慢选择排序(SelectionSort)

[基本思想]:每一趟(例如第i趟,i=1,…,n-1)在后面的n-i+1个待排序对象中选出关键字最小的对象,作为有序对象序列的第i个对象。待到第n-1趟作完,待排序对象只剩下1个,就不用再选了。简单选择排序(SimpleSelectionSort)

基本步骤为:i从1开始,直到n-1,进行n-1趟排序,第i趟的排序过程为:在一组对象r[i]~r[n](i=1,2,…,n-1)中选择具有最小关键字的对象;并和第i个对象进行交换;简单选择排序的算法

voidSelectSort(SqList&L){for(inti=1;i<L.length;++i)

{

intj=i; for(intk=i+1;k<=L.length;++k) if(L.r[j].key>L.r[k].key)j=k; if(i!=j){

ElemTypetemp=L.r[i];

L.r[i]=L.r[j];

L.r[j]=temp;

}

}}堆排序(HeapSort)

什么是堆?N个元素的序列{k1,k2,…,kn}当且仅当满足下列关系时,称为堆。ki≤k2i

ki≥k2i

ki≤k2i

+1

ki≥k2i

+1

给定一组关键字,初始态存储时是一个完全二叉树,则所有非终端结点的值均不大于(小于)其左右孩子结点的值。堆顶元素必为n个元素里最小(最大)值或堆排序:输出堆顶最小值后,使剩余的n-1个元素得又建成一个堆,则得到n个元素的次小值。反复执行得到一个有序序列。实现堆排序要解决的两个问题:(1)如何由一个无序序列建成一个堆?(2)如何在输出堆顶元素之后,调整剩余元素成为一个新的堆?解决第二个问题-----筛选:自堆顶到叶子调整解决第一个问题-----从第n/2个元素反复“筛选”。492525*211608123456082525*16214913654249252125*160808252125*1649交换1

号与6号对象,6号对象就位初始最大堆筛选--基于初始堆进行堆排序2525*082116491234561625*082521491365422525*210816491625*210825

49交换1

号与5号对象,5号对象就位从1号到5号重新调整为最大堆25*1608212549123456081625*25214913654225*16210825

4908162125*

25

49交换1

号与4号对象,4号对象就位从1号到4号重新调整为最大堆211625*082549123456081625*25214913654221160825*

25

49081621

25*

25

49交换1

号与3号对象,3号对象就位从1号到3号重新调整为最大堆160825*212549123456081625*25214913654216082125*

25

490816

21

25*

25

49交换1

号与2号对象,2号对象就位从1号到2号重新调整为最大堆一次筛选过程的算法

(最大堆向下调整的过程)voidHeapAdjust(HeapType&H,ints,intm){ElemTyperc=H.r[s];for(intj=2*s;j<=m;j*=2){ if((j<m)&&(LT(H.r[j].key,H.r[j+1].key)))++j; if(!(LT(rc.key,H.r[j].key)))break; H.r[s]=H.r[j];s=j;}H.r[s]=rc;}解决第二个问题-----建立初始的最大堆:从最后一个非终端结点即第[n/2]个元素开始向前反复筛选。212525*491608123456i212525*164908136542i21254925*1608初始关键字集合21254925*1608i=3时的局部调整212525*491608123456i492525*16210813654221254925*1608492521

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论