数据结构 Chap9学习资料_第1页
数据结构 Chap9学习资料_第2页
数据结构 Chap9学习资料_第3页
数据结构 Chap9学习资料_第4页
数据结构 Chap9学习资料_第5页
已阅读5页,还剩48页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

9.1概述9.2插入排序9.3交换排序9.4选择排序9.7各种排序方法的稳定性9.5归并排序9.6基数排序第9章排序9.1概述一、排序的定义三、内部排序和外部排序四、内部排序方法的分类二、稳定的排序和不稳定的排序一、什么是排序?排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。例如:将下列关键字序列52,49,80,36,14,58,61,23,97,75调整为14,23,36,49,52,58,61,75,80,97

一般情况下,假设含n个记录的序列为{R1,R2,…,Rn}其相应的关键字序列为{K1,K2,…,Kn}这些关键字相互之间可以进行比较,即在它们之间存在着这样一个关系:

Kp1≤Kp2≤…≤Kpn按此固有关系将上式记录序列重新排列为

{Rp1,Rp2,

…,Rpn}的操作称作排序。

设待排序记录序列中有关键字相等的记录,即ki=kj(i<>j),且在排序前Ri领先于Rj.

若排序后可以保证Ri仍领先于Rj,

则所用的排序方法称为稳定的;

若排序后不能保证Ri仍领先于Rj,

则所用的排序方法称为不稳定的.二、稳定的排序和不稳定的排序例如:

排序前

(56,34,47,23,66,18,82,

47)若排序后必有结果:

(18,23,34,47,47,56,66,82)则称该排序方法是稳定的;若排序后可能得结果:

(18,23,34,47,47,56,66,82)则称该排序方法是不稳定的。三、内部排序和外部排序若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序;

反之,若参加排序的记录数量很大,整个序列的排序过程不可能在内存中完成,则称此类排序问题为外部排序。四、内部排序的方法

内部排序的过程是一个逐步扩大记录的有序序列长度的过程。经过一趟排序有序序列区无序序列区有序序列区无序序列区

基于不同的“扩大”

有序序列长度的方法,内部排序方法大致可分下列几种类型:插入类交换类选择类

归并类其它方法1.插入类

将无序子序列中的一个或几个记录“插入”到有序序列中,从而增加记录的有序子序列的长度。2.交换类

通过“交换”无序序列中的记录从而得到其中关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。3.选择类

从记录的无序子序列中“选择”关键字最小或最大的记录,并将它加入到有序子序列中,以此方法增加记录的有序子序列的长度。4.归并类

通过“归并”两个或两个以上的记录有序子序列,逐步增加记录有序序列的长度。5.其它方法

9.2插入排序有序序列R[1..i-1]R[i]无序序列R[i..n]一趟直接插入排序的基本思想:有序序列R[1..i]无序序列R[i+1..n]实现“一趟插入排序”可分三步进行:3.将R[i]插入(复制)到R[j+1]的位置上。2.将R[j+1..i-1]中的所有记录均后移一个位置;1.在R[1..i-1]中查找R[i]的插入位置,

R[1..j].key

R[i].key<R[j+1..i-1].key;直接插入排序(基于顺序查找)不同的具体实现方法导致不同的算法描述折半插入排序(基于折半查找)希尔排序(基于逐趟缩小增量)一、直接插入排序

利用“顺序查找”实现“在R[1..i-1]中查找R[i]的插入位置”算法的实现要点:从R[i-1]起向前进行顺序查找,监视哨设置在R[0];R[0]=R[i];//设置“哨兵”循环结束表明R[i]的插入位置为j+1R[0]jR[i]for(j=i-1;R[0].key<R[j].key;--j)//从后往前找;

j=i-1插入位置

对于在查找过程中找到的那些关键字不小于R[i].key的记录,在查找的同时实现记录向后移动;for(j=i-1;R[0].key<R[j].key;--j)

R[j+1]=R[j]

;R[0]jR[i]j=i-1上述循环结束后可以直接进行“插入”插入位置令i=2,3,…,n,实现整个序列的排序。for(i=2;i<=n;++i)

if(R[i].key<R[i-1].key)

{R[0].key=R[i].key;

R[1..i-1]中查找R[i]的插入位置;

插入R[i];

}内部排序的时间分析:实现内部排序的基本操作有两个:(2)“移动”记录。(1)“比较”序列中两个关键字的大小;对于直接插入排序:最好的情况(关键字在记录序列中顺序有序):“比较”的次数:最坏的情况(关键字在记录序列中逆序有序):“比较”的次数:0“移动”的次数:“移动”的次数:

因为R[1..i-1]是一个按关键字有序的有序序列,则可以利用折半查找实现“在R[1..i-1]中查找R[i]的插入位置”,如此实现的插入排序为折半插入排序。它只能减少查找的次数不能减少移动的次数,因此与查找后移同时实现的直接插入排序比较,改进不大。二、折半插入排序14364952805861239775ilowhighmmlowlowmhigh14364952586180239775ilowhighmhighmhighmlow例如:再如:插入位置插入位置L.rL.r

由于插入排序的效率取决于:记录的个数及记录的原始序;

“宏观”调整:先“跳跃式”的分组进行排序,使得整个序列“基本有序”。(每组记录少)

“微观”调整:在整个序列“基本有序”后,再进行直接插入排序使整个序列“完全有序”。(记录的原始序优)三、希尔排序(缩小增量排序)

所以希尔排序的基本思想为:对待排记录序列先作“宏观”调整,再作“微观”调整。其中,d

称为增量,它的值在排序过程中从大到小逐渐缩小,直至最后一趟排序减为1。例如:将n个记录分成d个子序列:

{R[1],R[1+d],R[1+2d],…,R[1+kd]}{R[2],R[2+d],R[2+2d],…,R[2+kd]}…{R[d],R[2d],R[3d],…,R[kd],R[(k+1)d]}将记录序列跳跃式的分成若干组,分别对每组进行插入排序,组数不断减少,最后仅剩一组。例如:162512304711233691831

第一趟希尔排序,设增量d=547第二趟希尔排序,设增量d=330第三趟希尔排序,设增量d=1

91112161823253031364730936122523311611181612363123184711259

希尔排序的时间复杂度分析是一个数学上尚未解决的难题。增量序列d[1..t]的设计至关重要,目前没有统一定论,以经验为主。以经验,当n在一定范围内时,希尔排序的比较与移动次数约为:n1.3,当n→∞时:比较与移动次数约为n(log2n)2。9.3交换排序一、起泡排序二、一趟快速排序三、快速排序四、快速排序的时间分析一、起泡排序

假设在排序过程中,记录序列R[1..n]的状态为:第i趟起泡排序无序序列R[1..n-i+1]有序序列R[n-i+2..n]n-i+1无序序列R[1..n-i]有序序列R[n-i+1..n]比较相邻记录,将关键字最大的记录交换到

n-i+1的位置上算法一:voidbubblesort(recordtyper[],intlength);{n=length;change=true;

for(i=n;i>1&&change;--i)

{change=false;

change=true;

}}for(j=1;j<i;++j)if(r[j+1].key<r[j].key)

{x=r[j];r[j]=r[j+1];r[j+1]=x;}稳定?算法二:voidbubblesort(recordtyper[],intn);

{i=n;

while(i>1)

{

laste=1;for(j=1;j<i;j++)if(r[j+1].key<r[j].key)

{x=r[j];r[j]=r[j+1];r[j+1]=x;

laste=j;

}{记下进行交换的记录位置}

i=laste;

{本趟最后一次进行交换的记录位置}

}}5231978注意:2.算法一每经过一趟“起泡”则“i减1”,

但算法二并不是每趟如此。例如:2553157989i=7i=613i=21.起泡排序的结束条件为,

最后一趟没有进行“交换记录”。lastelaste1132时间分析:最好的情况(关键字在记录序列中顺序有序):只需进行一趟起泡“比较”的次数:最坏的情况(关键字在记录序列中逆序有序):需进行n-1趟起泡“比较”的次数:0“移动”的次数:“移动”的次数:n-1起泡排序一趟之后,使最大的记录定位到最后。如果一趟之后可使某记录(任意)定位在它应处的位置(在有序序列中),而将其余的无序序列以它为枢轴,分成两部分:比它小的放在它的前面,比它大的的放在它的后面,下一趟分别对前后的子序列排序,显然可加快速度。这就是快速排序二、一趟快速排序(一次划分)

目标:找一个记录,以它的关键字作为“枢轴”,凡其关键字小于枢轴的记录均移动至该记录之前;反之,凡关键字大于枢轴的记录均移动至该记录之后。致使一趟排序之后,记录的无序序列R[s..t]将分割成两部分:R[s..i-1]和R[i+1..t],且

R[j].key≤R[i].key≤R[j].key(s≤j≤i-1)

枢轴

(i+1≤j≤t)。stlowhigh设R[s]=52为枢轴

将R[high].key和枢轴的关键字进行比较,要求R[high].key≥

枢轴的关键字

将R[low].key和枢轴的关键字进行比较,要求R[low].key≤

枢轴的关键字high23low80high14low52例如R[0]52lowhighhighhighlow

可见,经过“一次划分”,将关键字序列

52,49,80,36,14,58,61,97,23,75调整为:23,49,14,36,(52)58,61,97,80,75

在调整过程中,设立了两个指针:low

和high,它们的初值分别为:s和t,

之后逐渐减小high,增加low,并保证

R[high].key≥52,和R[low].key≤52,否则进行记录的“交换”。一趟快速排序算法intQKpass(recordtyper[],ints,intt)/*本算法对r[s..t]进行一趟快速排序*/

{x=r[s];i=s;j=t;

while(i<j)

/*low用i表示,high用j表示*/{while(i<j)&&(r[j].key>=x.key)j=j-1;r[i]=r[j];

while(i<j)&&(r[i].key<=x.key)i=i+1;r[j]=r[i];

}r[i]=x;returni;}

三、快速排序

首先对无序的记录序列进行“一次划分”,之后分别对分割所得两个子序列“递归”进行快速排序。无序的记录序列无序记录子序列(1)无序子序列(2)枢轴一次划分分别进行快速排序voidQKsort(recordtyper[],intlow,inthigh);

/*对记录序列r[s..t]进行快速排序*/

{if(low<high){pos=QKpass(r,low,high);

/*对r[s..t]进行一趟划分,pos为枢轴*/

QKsort(r,low,pos-1);

/*对低子序列递归排序*/

QKsort(r,pos+1,high);

/*对高子序列递归排序*/

}}快速排序算法稳定?四、快速排序的时间分析假设一次划分所得枢轴位置i=k,则对n个记录进行快排所需时间:其中Tpass(n)为对n个记录进行一次划分所需时间。

若待排序列中记录的关键字是随机分布的,则k

取1至n

中任意一值的可能性相同。T(n)=Tpass(n)+T(k-1)+T(n-k)设Tavg(1)≤b则可得结果:结论:快速排序的时间复杂度为O(nlogn)由此可得快速排序所需时间的平均值为:

若待排记录的初始状态为按关键字有序时,快速排序将蜕化为起泡排序,其时间复杂度为O(n2)。

为避免出现这种情况,需在第一次划分之前,进行“予处理”,即:

先对r[s].key,r[t].key和r[

(s+t)/2].key进行相互比较,然后取关键字为“中间”

的记录为枢轴记录。9.4选择排序简单选择排序堆排序一、简单选择排序假设排序过程中,待排记录序列的状态为:有序序列R[1..i-1]无序序列R[i..n]

第i趟简单选择排序从中选出关键字最小的记录有序序列R[1..i]无序序列

R[i+1..n]简单选择排序算法voidSelectSort(RecordTyper[],intlength){n=length;for(i=1;i<=n-1;++i){k=i;

for(j=i+1;j<=n;++j)if(r[j].key<r[k].key)k=j;

if(k!=i){x=r[i];r[i]=r[k];r[k]=x;}}}稳定?时间性能分析

对n个记录进行简单选择排序,所需进行的关键字间的比较次数总计为:

移动记录的次数,最小值为0,

最大值为3(n-1)。二、堆排序堆是满足下列性质的数列{r1,r2,…,rn}:或堆的定义:(小堆)(大堆)rir2i

r2i+1

将该数列视作完全二叉树,r2i

是ri

的左孩子;r2i+1

是ri

的右孩子。则:1236276549817355403498例如:是堆14不排序方法:自学9.5归并排序

归并排序的过程基于下列基本思想进行:

将两个或两个以上的有序子序列“归并”为一个有序序列。在内部排序中,通常采用的是2-路归并排序。即:将两个位置相邻的有序子序列归并为一个有序的序列。有序序列r[l..n]有序子序列r[l..m]有序子序列r[m+1..n]这个操作对顺序表而言,是轻而易举的。归并例:(19)(13)(05)(27)(01)(26)(31)(16)(13,19)(05,27)(01,26)(16,31)(05,13,19,27)(01,16,26,31)(01,05,13,16,19,26,27,31)52,23,80,36,68,14[52,23,80][36,68,14][52,23][80][52][23,52][

23,52,80][36,68][14][36][68][36,68][14,36,68][14,23,36,52,68,80][23]完整的归并排序过程为:先分组再归并。当每个关键字的取值范围相同时,其排序可采用“分配”而非“比较”的方法进行。对于数字型或字符型的单关键字,可以看成是由多个数位或多个字符构成的多关键字,而此时每个“关键字”的取值范围是原关键字的基数。

对于数字型或字符型的“多关键字”

,可用LSD法,并采用

“分配-收集”再“分配-收集”…的办法实现排序,这就是基数排序。9.6基数排序例如:对下列这组关键字

{369,367,167,239,237,138,230,139}

首先按其“个位数”取值“分配”成10组,之后按从0至9的顺序将各组“收集”在一起;

然后按其“十位数”取值“分配”成10组,之后再按从0至9的顺序将各组“收集”

起来;

最后按其“百位数”

取值“分配”成10组,之后再按从0至9的顺序将各组“收集”

起来。

实现基数排序时,为减少所需辅助存储空间,可采用链表作存储结构。1.待排序记录以链表为存储结构;2.“分配”时,按当前“关键字位”将记录分配到不同的“链队列”中,每个队列中记录的当前“关键字位”相同;3.“收集”时,将各队列按关键字从小到大首尾相链构成一个新链表;4.按LSD对每个关键字位重复2、3,便可获得有序序列。具体方法:p→369→367→167→239→237→138→230→139进行第一次分配进行第一次收集p→230→230←→367←→167→237→367→167→237→138→369→239→139→369←→239→139→138←f[0]r[0]f[7]r[7]f[8]r[8]f[9]r[9]…例如:进行第二次分配p→230→237→138→239→139p→230→367→167→237→138→369→239

温馨提示

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

评论

0/150

提交评论