52
1 数数数数数数数 数数数数数数数 Data Structure Al Data Structure Al gorithms gorithms 烟烟烟烟烟烟烟烟烟烟烟烟 烟烟烟烟烟烟烟烟烟烟烟烟 烟烟烟烟烟烟烟烟烟烟 烟烟烟烟烟烟烟烟烟烟

数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

Embed Size (px)

DESCRIPTION

数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组. 9.4 选择排序. 选择排序的基本思想是: 每一趟在后面 n-i 个待排记录中选取关键字最小的记录作为有序序列中的第 i 个记录。. 选择排序有多种具体实现算法: 1) 简单选择排序 2) 锦标赛排序 3) 堆排序. 1 )简单选择排序. 思路简单: 每经过一趟比较就找出一个最小值,与待排序列最前面的位置互换即可。 - PowerPoint PPT Presentation

Citation preview

Page 1: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

1

数据结构与算法数据结构与算法Data Structure AlgorithData Structure Algorith

msms  

烟台南山学院信息科技学院烟台南山学院信息科技学院数据结构与算法教学组数据结构与算法教学组

Page 2: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

2

9.4 9.4 选择排序选择排序

选择排序有多种具体实现算法:

1) 简单选择排序

2) 锦标赛排序

3) 堆排序

选择排序的基本思想是:选择排序的基本思想是:每一趟在后面每一趟在后面 n-in-i 个待排记录个待排记录中选取关键字最小的记录作为有序序列中的第中选取关键字最小的记录作为有序序列中的第 i i 个记录个记录。。

Page 3: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

3

11 )简单选择排序)简单选择排序思路简单:思路简单:每经过一趟比较就找出一个最小值,与待每经过一趟比较就找出一个最小值,与待排序列最前面的位置互换即可。排序列最前面的位置互换即可。———— 首先,在首先,在 nn 个记录个记录中选择最小者放到中选择最小者放到 r[1]r[1] 位置;然后,从位置;然后,从剩余的剩余的 n-1n-1 个记录中选择最小者放到个记录中选择最小者放到 r[2r[2]] 位置;…如此进行下位置;…如此进行下去,直到全部有序为止。去,直到全部有序为止。

优点:优点:实现简单实现简单

缺点:缺点:每趟只能确定一个元素,表长为每趟只能确定一个元素,表长为 nn 时需要时需要 n-1n-1趟趟

前提:前提:顺序存储结构顺序存储结构

Page 4: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

4

例:关键字序列 T= ( 21 , 25 , 49 , 25* , 16 , 08 ),请给出简单选择排序的具体实现过程。原始序列: 21 , 25 , 49 , 25* , 16 ,08

第 1趟

第 2趟

第 3趟

第 4趟

第 5趟

08 , 25 , 49 , 25* , 16, 21

08 , 16, 49 , 25* , 25 , 21

08 , 16, 21 , 25* , 25 , 49

08 , 16, 21 , 25* , 25 , 49

08 , 16, 21 , 25* , 25 , 49

时间效率: O(nO(n22))——虽移动次数较少,但比较次数仍多。 空间效率: OO (( 11 ))——无需任何附加单元!算法的稳定性:不稳定不稳定——因为排序时, 25* 到了 25 的前

面。

最小值 08 与 r[1] 交换位置

Page 5: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

5

简单选择排序的算法如下:简单选择排序的算法如下:(亦可参见教材 P276 )

Void SelectSort(SqList &L ) {

for (i=1; i<L.length; ++i){

j = SelectMinKey(L,i);

if( i!=j ) r[i] r[j]; } } //SelectSort

// 对顺序表 L作简单选择排序

//选择第 i小的记录,并交换到位

//在 r[i…L.length] 中选择 key 最小的记录 // 与第 i个记录交

讨论:讨论:能否利用(能否利用(或记忆或记忆)首趟的)首趟的 n-1n-1 次比较所得次比较所得信息,从而尽量减少后续比较次数呢?信息,从而尽量减少后续比较次数呢?

答:答:能!能!请看——请看——锦标赛排序锦标赛排序和和堆排序堆排序!!

Page 6: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

6

22 ) 锦标赛排序 ) 锦标赛排序 ( 又称树形选择排序 )

基本思想:基本思想:与体育比赛时的淘汰赛类似。与体育比赛时的淘汰赛类似。 首先对 首先对 nn 个记录的关键字进行两两比较,得到 个记录的关键字进行两两比较,得到 nn/2/2 个优胜者个优胜者 (( 关键字小者关键字小者 )) ,作为第一步比较的结果保留下来。,作为第一步比较的结果保留下来。然后在这 然后在这 nn/2/2 个较小者之间再进行两两比较,…,如此重个较小者之间再进行两两比较,…,如此重复,直到选出最小关键字的记录为止。复,直到选出最小关键字的记录为止。优点:优点:减少比较次数,加快排序速度减少比较次数,加快排序速度缺点:缺点:空间效率低空间效率低

例:关键字序列 T= ( 21 , 25 , 49 , 25* , 16 , 08 ,63 ),请给出锦标赛排序的具体实现过程。

Page 7: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

7

08080808

Winner Winner (( 胜者胜者 ))

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

rr[1][1]

注:为便于自动处理,建议每个记录多开两个特殊分量:key otherinfo Index( 结点位置编号) Tag (是否参加比

较)

初态:初态: 补足补足 22kk( k=( k=loglog22nn )) 个叶子结点个叶子结点

第一趟:第一趟:

Page 8: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

8

第二趟:第二趟:

08080808

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

16161616

16161616

16161616 rr[2][2]

Winner Winner (( 胜者胜者 ))

求次小值 16时 ,只需比较22次,即只比较 loglog22nn -1 -1次。次。

令其 Tag = 0, 不参与比较

Page 9: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

9

令其 Tag = 0, 不参与比较

第三趟:第三趟:

16161616

21212121 16161616

16161616 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

rr[3][3]

Winner Winner (( 胜者胜者 ))

63636363

21212121

Page 10: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

10

08080808

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

63636363

21212121

第四趟:第四趟:

rr[4][4]

Winner Winner (( 胜者胜者 ))

25252525

25252525

25252525

Page 11: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

11

08080808

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

16161616

16161616

16161616

63636363

21212121

25252525

25252525

25252525

第五趟:第五趟:

rr[5][5]

Winner Winner (( 胜者胜者 ))

25*25*25*25*

25*25*25*25*

Page 12: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

12

08080808

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

16161616

16161616

16161616

63636363

21212121

25252525

25252525

25252525

25*25*25*25*

25*25*25*25*

第六趟:第六趟:

rr[6][6]

Winner Winner (( 胜者胜者 ))

49494949

49494949

49494949

Page 13: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

13

08080808

21212121 08080808

08080808 6363636325*25*25*25*21212121

21212121 25252525 49494949 25*25*25*25* 16161616 08080808 63636363

16161616

16161616

16161616

63636363

21212121

25252525

25252525

25252525

25*25*25*25*

25*25*25*25*

49494949

49494949

49494949

第七趟:第七趟: rr[7][7]Winner Winner (( 胜者胜者 ))

63636363

Page 14: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

14

算法分析:算法分析:•锦标赛排序构成的树是满锦标赛排序构成的树是满 ((完全)二叉树,其深度为 完全)二叉树,其深度为

loglog22n n +1 +1 ,其中 ,其中 nn 为待排序元素个数。为待排序元素个数。•时间复杂度:时间复杂度: O(O(nnloglog22nn) ) —n 个记录各自比较约 log2n 次•空间效率:空间效率: O(O(nn ) ) —胜者树的附加内结点共有 n’-1 个!•稳定性:稳定性:稳定 稳定 —左右结点相同者左为先

讨论:讨论: 在简单选择排序过程中,每当我们从表中选出在简单选择排序过程中,每当我们从表中选出最小最小元素之元素之后,再选后,再选次最小次最小元素时,必须把表中剩余元素再扫描一次。元素时,必须把表中剩余元素再扫描一次。这样,同一个元素会被扫描多次,浪费!这样,同一个元素会被扫描多次,浪费! 能否利用上次扫描的结果定出下一次的选择结果呢?能否利用上次扫描的结果定出下一次的选择结果呢? 答:能!答:能!请看——请看——堆排序堆排序算法算法

n’ =2k = 叶子总数

Page 15: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

15

33 ) 堆排序) 堆排序

1. 1. 什么是堆?什么是堆?堆的定义:堆的定义:设有设有 nn 个元素的序列 个元素的序列 kk11 ,, kk22 ,…,,…, kknn ,当,当且仅当满足下述关系之一时,称之为堆。 且仅当满足下述关系之一时,称之为堆。

kki i ≤≤ k k2i2i

kki i ≤≤ k k2i+12i+1

kki i ≥≥ kk2i2i

kki i ≥≥ k k2i+12i+1

或者或者 i=1, 2,… n/2i=1, 2,… n/2

解释:解释:如果让满足以上条件的元素序列 (如果让满足以上条件的元素序列 ( kk11 ,, kk22 ,…,,…, kk

nn )顺次排成一棵)顺次排成一棵完全二叉树,完全二叉树,则此树的特点是:则此树的特点是: 树中所有结点的值均大于(或小于)其左右孩子,此树树中所有结点的值均大于(或小于)其左右孩子,此树的根结点的根结点(即堆顶)(即堆顶)必最大(或最小)。必最大(或最小)。

2. 2. 怎样建堆?怎样建堆? 3. 3. 怎样堆排序?怎样堆排序?

Page 16: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

16

0808

2525

4646

4949

5858 6767

2 3

4 5 6

1

(大根堆)

9191

8585

6666

7676

5858 6767

2 3

4 5 6

1

55557

例:例:有序列 T1= ( 08, 25, 49, 46, 58, 67 )和序列 T2=( 91, 85, 76, 66, 58, 67, 55 ) ,判断它们是否 “堆”?

√ (小根堆) √

(小顶堆) (最小堆)

(大顶堆)(最大堆)

Page 17: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

17

步骤:步骤:从最后一个从最后一个非终端结点非终端结点开始往前逐步调整,让每个双开始往前逐步调整,让每个双亲大于(或小于)子女,直到根结点为止。亲大于(或小于)子女,直到根结点为止。

2121

2525

25*25*

4949

1616 0808

1

2 3

4 5 6

例:关键字序列 T= (21 , 25 , 49 , 25* , 16 , 08 ),请建大根堆。

2. 2. 怎样建堆?怎样建堆?

解:为便于理解,先将原始序列画成完全二叉树的形式:完全二叉树的第一个非终端结点完全二叉树的第一个非终端结点编号必为编号必为 n/2n/2 !!!! (( 性质性质 5)5)

注:终端结点(即叶子)没有任何子女,无需单独调整。

2121 i=3:i=3: 49大于 08 ,不必调整;i=2:i=2: 25大于 25* 和 16 ,也不必调整;i=1:i=1: 21 小于 25 和 49 ,要调整!

4949

而且 21还应当向下比较!!

Page 18: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

18

void HeapSort (HeapType &H ) {

//H//H 是顺序表,含有是顺序表,含有 H.rH.r[ ][ ] 和和 H.lengthH.length 两个分量两个分量 for ( i = length / 2; i >0; - - i ) //// 把把 rr[[1…length1…length]] 建成大根建成大根堆堆 HeapAdjust(r, i, length ); //// 使使 rr[[i…lengthi…length]]成为大根堆成为大根堆 ……

}

建堆算法 建堆算法 (( 其实是堆排序算法中的第一步)其实是堆排序算法中的第一步)

这是针对结点 i 的堆调整函数,其含义是:从结点 i开始到堆尾为止,自上向下比较,如果子女的值大于双亲结点的值,则互相交换,即把局部调整为大根堆。

参见教材参见教材 P281-282P281-282

Page 19: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

19

针对结点 i 的堆调整函数 HeapAdjust 如下:

HeapAdjust(r, i, m ){

current=i; child=2*i; temp=r[i];

while(child<=m){

if ( child<m && r[child].key<r[child+1].key )

child= child+1;

if(temp.key>=r[child].key)breack;

else { r[current]=r[child];

current= child; child=2* child; }

}

r[current]=temp;

} // HeapAdjust

//temp 是根, child 是其左孩子 //检查是否到达当前堆尾

//让 child指向两子女中的大者 //根大则不必调整,结束整个函数

// 否则子女中的大者上移

// 并继续向下整理!并继续向下整理! // 直到自下而上都满足堆定义,再安置老根

——从结点i开始到当前堆尾 m为止,自上向下比较,如果子女的值大于双亲结点的值,则互相交换,即把局部调整为大根堆。

//将根下降到子女位置

Page 20: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

20

关键:关键:将堆的当前顶点输出后,如何将剩余序将堆的当前顶点输出后,如何将剩余序列重新调整为堆?列重新调整为堆?

方法:方法:将当前顶点将当前顶点与堆尾记录交换与堆尾记录交换,然后,然后仿仿建建堆动作重新调整,如此反复直至排序结堆动作重新调整,如此反复直至排序结束。束。

3. 3. 怎样进行堆排序?怎样进行堆排序?

Page 21: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

21

08 25 21 25* 16 08 25 21 25* 16 494908 25 21 25* 16 08 25 21 25* 16 4949

交换 交换 11号与 号与 6 6 号记录号记录

4949

2525

25*25*

2121

1616 0808

1

2 3

4 5 6

49 25 21 25* 16 0849 25 21 25* 16 0849 25 21 25* 16 0849 25 21 25* 16 08

初始最大堆初始最大堆

2525

25*25* 1616

2121

1

3

654

2

0808

4949

例:例:对刚才建好的大根堆进行排序:对刚才建好的大根堆进行排序:

Page 22: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

22

16 25* 21 08 16 25* 21 08 25 4925 4916 25* 21 08 16 25* 21 08 25 4925 49

交换 交换 11号与 号与 5 5 号记录号记录

0808 25 2125 21 25* 16 25* 16 49490808 25 2125 21 25* 16 25* 16 4949

从 从 1 1 号到 号到 5 5 号 重新号 重新调整为最大堆调整为最大堆

0808

2525

25*25*

2121

1616 4949

1

2 3

4 5 6

1616

25*25*

0808 2525

2121

4949

1

3

654

20808

2525

25*25*

25 25 0808 21 21 25* 16 25* 16 494925 25 0808 21 21 25* 16 25* 16 4949

0808

25 25 25* 25* 2121 08 08 16 16 494925 25 25* 25* 2121 08 08 16 16 4949

Page 23: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

23

08 16 21 08 16 21 25* 25 4925* 25 4908 16 21 08 16 21 25* 25 4925* 25 49

交换 交换 1 1 号与 号与 4 4 号记录号记录

25* 16 21 08 25* 16 21 08 25 4925 4925* 16 21 08 25* 16 21 08 25 4925 49

从 从 11号到 号到 44号 重新号 重新调整为最大堆调整为最大堆

25*25*

1616

0808

2121

2525 4949

1

2 3

4 5 6

0808

1616

25*25* 2525

2121

4949

1

3

654

2

Page 24: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

24

08 16 08 16 21 25* 25 4921 25* 25 4908 16 08 16 21 25* 25 4921 25* 25 49

交换 交换 11号与号与 3 3 号记录号记录

21 16 08 21 16 08 25* 25 4925* 25 4921 16 08 21 16 08 25* 25 4925* 25 49

从 从 1 1 号到 号到 33号 重新号 重新调整为最大堆调整为最大堆

2121

1616

25*25*

0808

2525 4949

1

2 3

4 5 6

0808

1616

25*25* 2525

2121

4949

1

3

654

2

Page 25: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

25

08 08 16 21 25* 25 4916 21 25* 25 4908 08 16 21 25* 25 4916 21 25* 25 49

交换 交换 1 1 号与号与 2 2 号记录号记录

16 08 16 08 2121 25* 25 4925* 25 4916 08 16 08 2121 25* 25 4925* 25 49

从 从 1 1 号到 号到 2 2 号 重新号 重新调整为最大堆调整为最大堆

1616

0808

25*25*

2121

2525 4949

1

2 3

4 5 6

0808

1616

25*25* 2525

2121

4949

1

3

654

2

Page 26: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

26

void HeapSort (HeapType &H ) {

// 对顺序表 H 进行堆排序 for ( i = H.length / 2; i >0; -- i )

HeapAdjust(H,i, H.length ); // 初始堆 for ( i = H.length; i > 1; --i) {

H.r[1] H.r[i]; // 交换,要借用 temp

HeapAdjust( H, 1,i-1 ); // 重建最大堆 }

}

堆排序的算法堆排序的算法 参见教材参见教材 P281-282P281-282

这是针对结点 i 的堆调整函数(也是建堆函数),每次调用耗时 O(log2n)

Page 27: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

27

附附 11 :基于初始堆:基于初始堆进行堆排序的算法步骤:进行堆排序的算法步骤:

堆的第一个对象堆的第一个对象 VV[0][0] 具有最大的关键码,将具有最大的关键码,将 VV[0][0] 与与 VV[[nn]]对调,把具有最大关键码的对象交换到最后,再对前面的对调,把具有最大关键码的对象交换到最后,再对前面的nn-1-1 个对象,使用堆的调整算法,重新建立堆。结果具有次个对象,使用堆的调整算法,重新建立堆。结果具有次最大关键码的对象又上浮到堆顶,即最大关键码的对象又上浮到堆顶,即 VV[0][0] 位置。位置。

•再对调再对调 VV[0][0] 和和 VV[[n-n-1]1] ,调用对前,调用对前 nn-2-2 个对象重新调整,个对象重新调整,

…如此反复,最后得到全部排序好的对象序列。…如此反复,最后得到全部排序好的对象序列。

Page 28: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

28

比较左右孩子大小, j指向大者

比较大孩子与 rc 的大

小若大向上浮

rc = H.r[s]; j = 2s;

j<m &&H.r[j].key<H.r[j+1].key

++ j; // 指向右兄弟

j < m

rc.key > H.r[j].key

H.r[s]=H.r[j]; s=j;

j=2*j; //指向左孩子

N

N

N

Y

Y

Y

H.r[s…m] 中除 r[s]外,其他具有堆特征现调整 r[s] 的值 ,使 H.r[s…m] 为堆附附 22 ::

算法流程算法流程

Page 29: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

29

堆排序算法分析:堆排序算法分析:

• 时间效率:时间效率: O(O(nnloglog22nn)) 。。因为整个排序过程中需因为整个排序过程中需要调用要调用 nn-1-1 次次 HeapAdjust( ) 算法,而算法本身算法,而算法本身耗时为耗时为 loglog22nn ;;

• 空间效率:空间效率: O(1)O(1) 。。仅在第二个仅在第二个 forfor循环中交换循环中交换记录时用到一个临时变量记录时用到一个临时变量 temptemp。。

• 稳定性: 不稳定。稳定性: 不稳定。• 优点:优点:对小文件效果不明显,但对大文件有效。对小文件效果不明显,但对大文件有效。

Page 30: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

30

9.5 归并排序归并排序的基本思想是:归并排序的基本思想是:将两个(或以上)的有序将两个(或以上)的有序表组成新的有序表。表组成新的有序表。

更实际的意义:更实际的意义:可以把一个长度为可以把一个长度为 n n 的无序序列看成是 的无序序列看成是 n n 个长度为 个长度为 1 1 的有序子序列的有序子序列 ,首先做两两归并,得到 ,首先做两两归并,得到 n n

/ 2/ 2 个长度为 个长度为 2 2 的子序列 ;再做两两归并,…,如此重复,的子序列 ;再做两两归并,…,如此重复,直到最后得到一个长度为 直到最后得到一个长度为 n n 的有序序列。的有序序列。

例:例:关键字序列 T= ( 21 , 25 , 49 , 25* , 93 ,62 , 72 , 08 , 37 , 16 , 54 ),请给出归并排序的具体实现过程。

Page 31: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

31

2121 2525 25*25* 9393 6262 7272 0808 3737 1616 54544949

2121 2525 25*25* 4949 6262 9393 0808 7272 1616 3737 5454

1616 3737 5454

2121 2525 25*25* 4949 0808 6262 7272 9393

0808 2121 2525 25*25* 4949 6262 7272 9393

0808 1616 2121 2525 25*25* 3737 4949 5454 6262 7272 9393

lenlen=1=1

lenlen=2=2

lenlen=4=4

lenlen=8=8

lenlen=16=16

1616 3737 5454

整个归并排序仅需整个归并排序仅需 loglog22n n 趟趟

Page 32: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

32

一趟归并排序算法一趟归并排序算法 : (: ( 两路有序并为一路两路有序并为一路 )) 参见教材参见教材 P2P28383

void MergeMerge (SR , &TR , i, m, n) {

// 将有序的 SR[i…m] 和 SR[m+1…n]归并为有序的 TR[i…

n]

for(k=i , j=m+1; i<=m && j<=ni<=m && j<=n; ++k ) {

if ( SR[i]<= SR[j] )TR[k]=SR[i++];

else TR[k]=SR[j++]; // 将 SR 中记录由小到大地并入TR

}

if (i<=m) TR[k…n]=SR[i…m]; // 将剩余的 SR[i…m] 复制到TR

if (j<=n) TR[k…n]=SR[j…n]; // 将剩余的 SR[j…n] 复制到 T

R

} // Merge

Page 33: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

33

void MSort MSort (SR , &TR1 , s, t) { // 将无序的 SR[s…t]归并排序为 TR1[s…t] if ( s==t )TR1[s]=SR[s]; // 当 len=1 时返回 else { m=(s+t)/2; // 将 SR [s…t]平分为 SR [s…m] 和 SR [m+1…t] MSort MSort (SR , &TR2 , s, m); // 将 SR 一分为二 , 2 分为 4… // 递归地将 SR [s…m]归并为有序的 TR2[s…m] MSortMSort (SR , &TR2 , m+1, t ); // 递归地将 SR [m+1…t]归并为有序的 TR2[m+1…t] MergeMerge(TR2 , TR1 , s, m, t ); // 将 TR2 [s…m] 和 TR2 [m+1…t]归并到 TR1 [s…t] } } // MSort

递归形式的两路归并排序算法递归形式的两路归并排序算法 : : 参见教材参见教材 P284P284 ( ( 一路无序变为有序一路无序变为有序 ))

简言之,先由“长”无序变成“短”有序, 再从“短”有序归并为“长”有序。

初次调用时为( L, L, 1, length )

Page 34: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

34

归并排序算法分析:归并排序算法分析:

• 时间效率:时间效率: O(O(nnloglog22nn))因为在递归的归并排序算法中,函数 Merge( )做一趟两路归并排序,需要调用 merge ( )函数 n/(2*len) O(n/len) 次,函数 Merge( )调用 Merge( )正好 log2n 次,而每次 merge( )要执行比较 O(len) 次,所以算法总的时间复杂度为 O(nlog2n) 。

• 空间效率:空间效率: O(O(nn) ) 因为需要一个与原始序列同样大小的辅助序列( TR )。这正是此算法的缺点。

• 稳定性:稳定性:稳定稳定

Page 35: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

35

9.6 基数排序 (Radix Sort)(Radix Sort)

要讨论的问题:要讨论的问题:1. 1. 什么是“什么是“多关键字多关键字”排序?实现方法?”排序?实现方法?2. 2. 单逻辑关键字怎样“单逻辑关键字怎样“按位值按位值”排序?”排序?

基数排序的基本思想是:基数排序的基本思想是:

借助多关键字排序的思想对单逻辑关键字进行排借助多关键字排序的思想对单逻辑关键字进行排序。即:用关键字序。即:用关键字不同的位值不同的位值进行排序。进行排序。

Page 36: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

36

1. 1. 什么是“什么是“多关键字多关键字”排序?实现方法?”排序?实现方法?例例 11 :对一副扑克牌该如何排序?:对一副扑克牌该如何排序? 若规定花色和面值的顺序关系为:若规定花色和面值的顺序关系为: 花色花色:: 面值:面值: 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A

则则可以可以先按花色先按花色排序,花色相同者排序,花色相同者再按面值再按面值排序排序;; 也可以先按面值排序,面值相同者再按花色排序。也可以先按面值排序,面值相同者再按花色排序。例例 22 :职工分房该如何排序?:职工分房该如何排序? 河大规定:河大规定:先以总分先以总分排序(职称分+工龄分);排序(职称分+工龄分);总分相同者,总分相同者,再按配偶总分再按配偶总分排序,其次按配偶职称、排序,其次按配偶职称、工龄、人口……等等排序。工龄、人口……等等排序。

以上两例都是典型的多关键字排序!

Page 37: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

37

多关键字排序的实现方法通常有两种:多关键字排序的实现方法通常有两种:• 最高位优先法最高位优先法 MSD (Most Significant Digit first)MSD (Most Significant Digit first)

例:例:对一副扑克牌该如何排序?对一副扑克牌该如何排序?答:答:若规定若规定花色为第一花色为第一关键字(高位),关键字(高位),面值为第二面值为第二关键字关键字(低位),则使用(低位),则使用 MSDMSD 和和 LSDLSD方法都可以达到排序目的。方法都可以达到排序目的。

MSDMSD方法的思路:方法的思路:先设立先设立 44 个花色“箱”,将全部牌按花色个花色“箱”,将全部牌按花色分别归入分别归入 44 个箱内(每个箱中有个箱内(每个箱中有 1313张牌);然后对每个箱中张牌);然后对每个箱中的牌按面值进行插入排序(或其它稳定算法)。的牌按面值进行插入排序(或其它稳定算法)。

LSDLSD方法的思路:方法的思路:先按面值分成先按面值分成 1313 堆(每堆堆(每堆 44张牌),然后张牌),然后对每堆中的牌按花色进行排序(用插入排序等稳定的算法)。对每堆中的牌按花色进行排序(用插入排序等稳定的算法)。

想一想:用哪种方法更快些想一想:用哪种方法更快些??

• 最低位优先法最低位优先法 LSD (Least Significant Digit first)LSD (Least Significant Digit first)

Page 38: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

38

2. 2. 单逻辑单逻辑关键字怎样“关键字怎样“按位值按位值”排序?”排序?设设 n n 个记录的序列为:个记录的序列为: {V0, V1, …, Vn-1 }{V0, V1, …, Vn-1 },可以把,可以把每个记录每个记录 Vi Vi 的单关键码 的单关键码 Ki Ki 看成是一个看成是一个 dd元组(元组( Ki1,Ki1, Ki2, …, Kid Ki2, …, Kid),则其中的每一个分量),则其中的每一个分量 Kij ( 1Kij ( 1 j j d ) d ) 也可看成是一个关键字。也可看成是一个关键字。

44

注注 11 :: KKii11 =最高位=最高位,, KKiidd =最低位;=最低位; KKii 共有共有 dd 位,可看成位,可看成 dd 元元组;组;注注 22 :: 每个分量 每个分量 KKiijj (1 (1 jj dd ) ) 有有 radixradix 种取值,则称种取值,则称 radixradix 为为基数基数。。

2626

(9, 8, 4)(9, 8, 4) (0, 1, …, 9)(0, 1, …, 9)

(( a, b, …, a, b, …, zz ))

(d, i, a, n)(d, i, a, n)

33 1010例例 11 ::关键码关键码 984984 可以看成是可以看成是 元组;基数元组;基数 radixradix 为为 。。

例例 22 ::关键码关键码 diandian 可以看成是可以看成是 元组;基数元组;基数 radixradix 为为 。。

思路:思路:

Page 39: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

39

因为有分组,故此算法需递归实现。

讨论:讨论:是借用 MSD 方式来排序呢,还是借用 LSD 方式?

例:初始关键字序列 T= ( 32, 13, 27, 32*, 19 , 33 ),请分别用 MSD 和 LSD 进行排序,并讨论其优缺点。

法 1 ( MSD ):原始序列: 32, 13, 27, 32*, 19 , 33 先按高位 KKii11 排序:( 13, 19 ) , 27, ( 32, 32* ,33 ) 再按低位 KKii2 2 排序 : 13, 19 , 27, 32, 32*, 33

法 2 ( LSD ): 原始序列: 32, 13, 27, 32*, 19 ,33 先按低位 KKii22 排序: 32, 32*, 13, 33, 27, 19 再按高位 KKii11 排序: 13, 19 , 27, 32, 32*, 33

无需分组,易编程实现!

Page 40: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

40

例:例: T=T= (( 0202 ,, 7777 ,, 7070 ,, 5454 ,, 6464 ,, 2121 ,, 5555 ,, 1111 ),用),用LSDLSD 排序。排序。分析:分析:①①各关键字可视为各关键字可视为 22 元组元组;②每位的取值范围是:;②每位的取值范围是: 0-90-9 ;即;即基基数数 radixradix == 10 10 。。因此,特设置因此,特设置 1010 个队列,并编号为个队列,并编号为 0-90-9 。。

11

55

21

64

54

70

77

02

原始序列原始序列

1122334455667788

先对低位扫描先对低位扫描 出队出队

00112233445566778899

1010 个队列个队列

计算机怎样实现计算机怎样实现 LSDLSD 算法?算法?

分配分配过程过程

收集收集过程过程

下一步下一步

77

55

64

54

02

11

21

701122334455667788

出队后序列出队后序列

77

55

54 , 64

21 , 11

70

02

又称散列过程!

Page 41: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

41

00112233445566778899

再次入队再次入队

再次出队再次出队再对高位扫描再对高位扫描

小结:小结:排序时经过了反复的“分配”和“收集”过程。当对关键字所有的位进行扫描排序后,整个序列便从无序变为有序了。

77

55

64

54

02

11

21

701122334455667788

出队后序列出队后序列

70 , 77

64

54 , 55

21

1102

再次再次分配分配 再次再次

收集收集 77

70

64

55

54

21

11

02

再次出队后序列再次出队后序列

这种这种 LSDLSD排序方法称为:排序方法称为:基数排序基数排序

Page 42: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

42

讨论:讨论:所用队列是顺序结构,浪费空间,能否改用链式结构?

用链队列来实现基数排序用链队列来实现基数排序—— 链式基数排序链式基数排序

实现思路:实现思路: 针对 针对 d d 元组元组中的每一位分量,中的每一位分量,把原始把原始链表链表中的所有记录中的所有记录 , , 按按 KKiijj 的取值,让 的取值,让 jj = = dd, , dd--1, …, 11, …, 1 ,,

① ① 先“先“分配分配”到”到 radixradix 个个链队列链队列中去;中去;② ② 然后再按各然后再按各链队列链队列的顺序,依次把记录从的顺序,依次把记录从链队列链队列中中““收集收集”起来;”起来;

③ ③ 分别用这种“分配”、“收集”的运算逐趟进行排序;分别用这种“分配”、“收集”的运算逐趟进行排序;④ ④ 在最后一趟“分配”、“收集” 完成后,所有记录在最后一趟“分配”、“收集” 完成后,所有记录

就按其关键码的值从小到大排好序了。就按其关键码的值从小到大排好序了。

能!

Page 43: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

43

请实现以下关键字序列的请实现以下关键字序列的链式基数排序链式基数排序::T=T= (( 614614,, 738738 ,, 921921 ,, 485485 ,, 637637 , , 101101 ,, 215215 ,, 530530 ,, 7979

00 ,, 306306 ))

例例 ::

614614614614 921921921921 485485485485 637637637637738738738738 101101101101 215215215215 530530530530 790790790790 306306306306

第一趟分配第一趟分配e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9]

614614 738738921921 485485 637637

101101 215215

530530

790790

306306

f[0] f[1] f[2] f[3] f[4] f[5] f[6] f[7] f[8] f[9]

原始序列链表:原始序列链表:r[0]→

(从最低位 (从最低位 i i = 3= 3 开始排序,开始排序, f[ ] 是队首指针,是队首指针, e[ ] 为队尾指针)为队尾指针)

第一趟收集第一趟收集(让队尾指针(让队尾指针 e[i] 链接到下一非空队首指针链接到下一非空队首指针 f[i+1 ] 即即可)可) 530530 790790 921921 101101 614614 485485 215215 306306 637637 738738r[0]→

Page 44: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

44

第一趟收集的结果:第一趟收集的结果:

e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9]

614614

738738

921921 485485637637

101101

215215

530530 790790

306306

f[0] f[1] f[2] f[3] f[4] f[5] f[6] f[7] f[8] f[9]

第二趟分配第二趟分配(按次低位 (按次低位 ii = 2 = 2 ))

530530 790790 921921 101101 614614 485485 215215 306306 637637 738738

第二趟收集第二趟收集(让队尾指针(让队尾指针 e[i] 链接到下一非空队首指针链接到下一非空队首指针 f[i+1 ] ))530530 790790921921101101 614614 485485215215306306 637637 738738

r[0]→

r[0]→

Page 45: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

45

第二趟收集的结果:第二趟收集的结果:530530 790790921921101101 614614 485485215215306306 637637 738738

e[0] e[1] e[2] e[3] e[4] e[5] e[6] e[7] e[8] e[9]

614614 738738 921921485485

637637

101101 215215 530530

790790

306306

f[0] f[1] f[2] f[3] f[4] f[5] f[6] f[7] f[8] f[9]

第三趟分配第三趟分配(按最高位 (按最高位 ii = 1 = 1 ))

第三趟收集第三趟收集(让队尾指针(让队尾指针 e[i] 链接到下一非空队首指针链接到下一非空队首指针 f[i+1 ] ))

530530 790790 921921101101 614614485485215215 306306 637637 738738

r[0]→

r[0]→

排序结束!排序结束!

Page 46: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

46

1. 排序前后的 n 个记录都用顺序表 r[ ] 存储,但建议增开 n 个指针分量(转为静态链表形式);这样在记录重排时不必移动数据,只需修改各记录的链接指针即可。

2. 在 radix 个队列中,每个队列都要设置两 个指针: int f [radix]指示队头 ( f[ j ] 初始为空); int e [radix] 指向队尾( e[ j ] 不必单独初始化 ) ;分配到同一队列的关键码要用链接指针链接起来。 (注:以上一共增开了 n+2 radix 个附加指针分量)3. 待排序记录存入 r[ ] 中, r[0] 作为头结点;每个记录都包含 key 分量、 othernifo 分量和指针域 intint next 分量。

另外,为能单独表示单关键码 key 的各位,将 key改用向量 key[0…d-1] 来表示之,这样:

第 p 个记录的关键码的第 i 位可表示为: r[p].key[i];

第 p 个记录的指针分量可表示为: r[p].next

如何编程实现?如何编程实现? 先作若干说明:先作若干说明:

Page 47: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

47

队列初始化队列初始化

p = 0?p = 0?

jj=r[p].key[i]=r[p].key[i]

f(f(jj) = 0?) = 0?

f(f(jj) = p;) = p; r[r[e[j]].next=p;].next=p;

e(j) = p;e(j) = p;

p =r[p].next;p =r[p].next;

end;end;NN

YY

YY

NN

//// 取第取第 pp 个关键字的第个关键字的第 i i 位位

//// 将将 pp指向下一个关键字指向下一个关键字

队不空,则新元素应链到原队尾元素之后

P 是关键字序列 r[ ] 的指针分量

队首为空吗?空则f(j) =新入队元素

队尾=新入队的元素地址

一趟“分配”过程的算法流程一趟“分配”过程的算法流程

Page 48: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

48

void RadixSort (&list, int d, int radix ) { int f[radix], e[radix]; for ( int i = 1; i < n; i++ ) r[i].next=i+1; r[n].next=0; //静态链表初始化,将各记录顺次链接。 int p= 1; //p 是链表元素的地址指针 for ( i = d-1; i >= 0; i-- ) { // 开始做 d 趟分配 /收集 , i 是 key 的第 i 位 for ( int j = 0; j < radix; j++ ) f[j] = 0; // 初态=各队列清空 while ( p!= 0 ) { // 开始将 n 个记录分配到 radix 个队列 int k = r[p]. key[i]; // 取当前记录之 key 分量的第 i 位 if ( f[k] == 0) f [k] =p; //若第 k 个队列空 , 此记录成为队首;

else r[e[k]].next=p; //若队列不空 ,链入原队尾元素之后 e[k] =p; //修改队尾指针,该记录成为新的队尾 p= r[p].next; } / / 选下一关键字,直到本趟分配完

链表基数排序的算法:链表基数排序的算法:

Page 49: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

49

j = 0; // 开始从 0号队列(总共 radix 个队)开始收集 while ( f [j] == 0 ) j++; //若是空队列则跳过 r[0].next=p = f [j]; // 建立本趟收集链表的头指针 int last = e[j]; // 建立本趟收集链表的尾指针 for ( k = j+1; k < radix; k++) //逐个队列链接(收集) if ( f [k] ) { //若队列非空 r[last].next=f [k]; last = e[k]; //队尾指针链接 } r[last].next=0; // 本趟收集链表之尾部应为 0 }} // RadixSort 注:在此算法中,数组 r[n]被反复使用,用来存放原始序

列和每趟收集的结果。记录从未移动,仅指针改变。

Page 50: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

50

基数排序算法分析基数排序算法分析

• 假设有假设有 n n 个记录个记录 , , 每个记录的关键字有每个记录的关键字有 d d 位,每个关键位,每个关键字的取值有字的取值有 radixradix 个个 , , 则需要则需要 radixradix 个队列个队列 , , 进行进行 d d 趟趟“分配”与“收集”。因此时间复杂度:“分配”与“收集”。因此时间复杂度: O ( d ( n+radixO ( d ( n+radix ) ) ) ) 。。

• 基数排序需要增加基数排序需要增加 n+2radixn+2radix 个附加链接指针,空间效率个附加链接指针,空间效率低低

空间复杂度:空间复杂度: OO (( radixradix )) ..

• 稳定性:稳定。稳定性:稳定。 (( 一直前后有序一直前后有序 )) 。。

用途:用途:若基数若基数 radixradix 相同,对于记录个数较多而关键码位数相同,对于记录个数较多而关键码位数较少的情况,使用链式基数排序较好。较少的情况,使用链式基数排序较好。

特点:特点:不用比较和移动,改用分配和收集,时间效率高!不用比较和移动,改用分配和收集,时间效率高!

Page 51: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

51

各种内部排序方法的比较 ( 教材 P289 )

排序方法 排序方法 最好情况 最好情况 平均时间 平均时间 最坏情况最坏情况 辅助存储辅助存储 稳定性 稳定性 简单排序 O(n) O(n2) O(n2) O(1 ) 稳定 快速排序 O(nlgn ) O(nlgn) O(n2) O(lgn) 不稳定 堆排序 O(nlgn ) O(nlgn ) O(nlgn) O(1 ) 不稳定 归并排序 O(nlgn ) O(nlgn ) O(nlgn) O(n ) 稳定基数排序 O(d(n+rd)) O(d(n+rd)

)O(d(n+rd))

O(rd) 稳定

简单选择 O(n2) O(n2) O(n2) O(1 ) 不稳定 直接插入 O(n) O(n2) O(n2) O(1 ) 稳定 折半插入 O(nlgn ) O(nlgn ) O(nlgn ) O(1 ) 稳定冒泡 O(n) O(n2) O(n2) O(1 ) 稳定

Page 52: 数据结构与算法 Data Structure Algorithms 烟台南山学院信息科技学院 数据结构与算法教学组

52

讨论:若初始记录基本无序,则选用哪些排序方法比较适合?若初始记录基本无序,则最好选用哪些排序方法?

答:对基本有序的情况,可选用堆排序、冒泡排序、归并排序等方法; 在基本无序的情况下,最好选用快速排序、希尔排序。

想一想:能选用折半排序么?