分治法在归并排序和快速排序中的应用

http://blog.csdn.net/qtyl1988/article/details/51328791

2016

归并排序

归并排序和快速排序都使用了“分治”策略(divide-and-conquer)。对于数组A[p..r],归并排序先把数组从中间分开,形成两个具有(p+r)/2个元素的子数组(divide);然后,分别对这两个子数组递归地进行归并排序(conquer),当子数组只包含一个元素时到达递归出口;最后,将两个排好序的子数组合并起来,形成有序数组(combine)。

归并排序算法如下:

MERGE-SORT(A, p, r) if p

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

一些问题可以在归并排序的基础上得到解决,典型的有“计算数组的逆序数”等。

计算数组的逆序数

给定包含n个不同元素的数组A[1..n],如果存在i A[j],则(i, j)称为数组A的一个逆序。数组包含所有逆序的数量成为数组的逆序数。例如,对于数组[2, 3, 8, 6, 1],它的逆序有(2, 1), (3, 1), (8, 6), (8, 1), (6, 1),所以该数组的逆序数为5。

如果对数组进行插入排序,会发现每次“插入”都能消除若干逆序。插入排序算法如下:

INSERTION-SORT(A) for j = 2 to A.length key = A[j] i = j - 1 while i > 0 and A[i] > key A[i + 1] = A[i] i = i - 1 A[i + 1] = key1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

可以看出,消除逆序的操作发生在while循环中:每执行一次循环体都会消除一个逆序。当所有逆序都被消除后,就完成了插入排序。所以,可以通过在插入排序中加入计数器的方法计算数组逆序数。这样做的时间复杂度为O(n2)。

既然排序的过程就是消除逆序的过程,我们可以考虑修改归并排序来计算数组逆序数:首先,将数组A[p..r]分成两个分别具有(p+r)/2个元素的子数组;然后,分别计算两个子数组中的逆序数。需要注意的是,简单相加两个子数组的逆序数并不能得出原数组的逆序数,因为原数组还有一部分逆序存在于合并两个子数组的过程中,所以原数组的逆序数是两个子数组逆序数之和加上合并过程中消除的逆序数。

对于已经从小到大排好序的子数组A[p..q]和A[q+1..r],令n1和n2分别表示两个子数组的长度。对于 i∈[p,q],j∈[q+1,r],如果A[j]

COUNT-INVERSIONS(A, p, r) if p

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

快速排序

与归并排序类似,快速排序的第一步也是把数组A[p..r]划分成两个子数组。快速排序希望其中一个子数组中的所有元素都比另一个子数组中的元素小,于是采用了如下划分(partition)方式:先从数组A[p..r]中选出一个元素作为“轴”(pivot),所有大于轴的元素作为一个子数组,把它们放到A[p..q-1]位置上,所有不大于轴的元素作为另一个子数组,把它们放到A[q+1..r]位置上,最后把轴元素放到A[q]位置上,这样就完成了一次划分,可以看出,轴元素已经被固定在了A[q]位置上,在后续的排序过程中,位置不再改变;然后,分别对A[p..q-1]和A[q+1..r]递归地进行快速排序。由于A[p..q-1]中的所有元素均小于A[q+1..r]中的元素,所以这两个子数组分别排好序后,排序过程就结束了,不必像归并排序那样再做一次合并操作。

快速排序算法如下:

QUICKSORT(A, p, r) if p

2

3

4

5

6

7

8

9

10

11

12

13

14

15

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

众所周知,快速排序的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n2)。最坏情况发生在每次划分(partition)都极度不平衡的时候,即对于一个n元素数组,每次划分都将数组分为长度分别为1和n-1的两个子数组,这时,需要进行O(n)次递归调用,导致了O(n2)的时间复杂度。

为了减少最坏情况的发生,可以在每次排序前随机选择一个元素作为轴,然后将这个元素与A[r]交换,这样,数组中每个元素被选为轴的概率相等。于是,就有了随机版的快速排序算法:

RANDOMIZED-QUICKSORT(A, p, r) if p

2

3

4

5

6

7

8

9

10

1

2

3

4

5

6

7

8

9

10

一些问题可以在快速排序的基础上得到解决,典型的有“查找第k小的元素”等。

查找第i小的元素

给定一个数组,可以利用分治法找到数组中第i小的元素。具体思路是:将数组划分成两个子数组,使其中一个子数组中的所有元素均小于另一个子数组中的元素(divide);然后,判断第k小的元素位于哪个子数组中,并在那个子数组中继续进行划分和判断,直到找到第k小的元素(conquer)。显然,划分过程可以利用快速排序的RANDOMIZED-PARTITION方法。与快速排序不同的是,每完成一次划分,只需在包含第i小元素的子数组中进行后续操作,不再对另一个子数组进行操作。这样,平均算法复杂度为 O(n)。查找第i小元素的算法如下:

RANDOMIZED-SELECT(A, p, r, i) if p == r return A[p] q = RANDOMIZED-PARTITION(A, p, r) k = q - p + 1 if k == i return A[q] elseif i

2

3

4

5

6

7

8

9

10

11

1

2

3

4

5

6

7

8

9

10

11

这个问题的一个变体是“查找数组中最小的i个元素”。实际上,只要通过反复调用RANDOMIZED-PARTITION方法找到第i小元素,该元素左侧的子数组就是数组中最小的i个元素。

这个问题的另一个变体是“查找数组中出现次数超过一半的元素”。显然,如果一个元素在数组中出现的次数超过一半,那么,只要将数组排序,这个元素必然出现在排序后的数组的中间位置。所以,该问题等价于“查找第n/2小的元素”,其中n是数组元素个数。


相关文章

  • 笔试题目总结之四 常用数据结构与算法
  • 数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易.在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考察一个人这方面的能力,把每种结构和算法都问一遍不太现实.所以,实际的情况是,企业一般考察一些看起来很基本的概念和算法,或者是一些变 ...

  • 归并排序算法论文
  • 归并排序算法解决排序问题 目录 1引言 ...................................................................................................... 2 2.归并排序的基本思想 ............. ...

  • 算法与数据结构习题2
  • <算法与数据结构>习题2 一.单项选择题 1. 在数组A 8×10中,行列下标从0开始,每一个数组元素占用3个字节存储,所有数据元素相继存放在一个地址连续的存储空间中,则存放该数组至少需要的字节数是( ). A .240 B .100 C .80 D .270 2. 如果把由树转换得到的 ...

  • 各种排序算法的优缺点
  • 一.冒泡排序 已知一组无序数据a[1].a[2].--a[n],需将其按升序排列.首先比较a[1]与 a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变.再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变.再比 较a[3]与a[4],以此类推,最后比较a[n-1] ...

  • 各种排序方法的比较和选择
  • 按平均时间将排序分为四类: (1)平方阶(O(n2))排序 一般称为简单排序,例如直接插入.直接选择和冒泡排序: (2)线性对数阶(O(nlgn))排序 如快速.堆和归并排序: (3)O(n1+£) 阶排序 £是介于0和1之间的常数,即0 (4)线性阶(O(n))排序 如桶.箱和基数排序. 各种排序 ...

  • 数据结构教学大纲
  • 数据结构教学大纲 (56学时) 一.课程性质.适用专业及层次 本课程是我院计算机专业的一门综合性的专业基础课.主要介绍如何合理地组织数据.有效地存储和处理数据,正确地设计算法以及对算法的分析和评价.通过本课程的学习,使学生深透地理解数据结构的逻辑结构和物理结构的基本概念以及有关算法,培养基本的.良好 ...

  • 数据结构内部排序算法比较
  • 内部排序算法比较 第一章 问题描述 排序是数据结构中重要的一个部分,也是在实际开发中易遇到的问题,所以研究各种排算法的时间消耗对于在实际应用当中很有必要通过分析实际结合算法的特性进行选择和使用哪种算法可以使实际问题得到更好更充分的解决!该系统通过对各种内部排序算法如直接插入排序,冒泡排序,简单选择排 ...

  • [数据结构]课程教学大纲
  • <数据结构>课程教学大纲--2012版 一.课程基本信息 课程名称:数据结构 英文名称:Data Structure 课程编码: 11107C/11207C 课程类别:专业主干课 总学时: 64学时(含实验16学时) 总学分: 4 适用专业:计算机科学与技术/网络工程方向 先修课程:高级 ...

  • 20**年燕山大学 数据结构 硕士研究生考试大纲
  • 数据结构 发布日期:2015-7-16 11:15:22 新闻来自:本站原创 第一章 绪论 [目的与要求]: 深刻理解数据结构的概念,掌握数据结构的要素:掌握数据元素的逻辑结构:掌握数据元素的存贮结构:理解数据结构与算法的联系:了解算法的效率及存贮空间的度量. [本章主要内容]: 1.1 什么是数据 ...

© 2024 范文中心 | 联系我们 webmaster# onjobs.com.cn