41
第2第 第 第 第 第第第第 第第第第 ---- 第第第第

第 2 章 分 治 法

  • Upload
    braima

  • View
    133

  • Download
    0

Embed Size (px)

DESCRIPTION

第 2 章 分 治 法. 分而治之,各个击破 ---- 合并得解. 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,解题所需的时间往往也越少,从而也较容易处理。例如,对于 n 个元素的排序问题,当 n=1 时,不需任何计算,当 n=2 时,只要作一次比较即可排好序。当 n=3 时只要作两次比较即可 … ., 而当 n 较大时,问题就不那么容易处理了。要想直接解决一个较大的问题,有时是相当困难的。 - PowerPoint PPT Presentation

Citation preview

Page 1: 第 2 章  分 治 法

第 2 章 分 治 法 分而治之,各个击破 ---- 合并得解

Page 2: 第 2 章  分 治 法

任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,解题所需的时间往往也越少,从而也较容易处理。例如,对于 n 个元素的排序问题,当 n=1 时,不需任何计算,当 n=2 时,只要作一次比较即可排好序。当 n=3 时只要作两次比较即可… ., 而当 n 较大时,问题就不那么容易处理了。要想直接解决一个较大的问题,有时是相当困难的。 分治法的设计思想是:将一个难以解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。如果原问题可分割成 k 个子问题, 且这些子问题都可解,并可利用这些子问题的解而求出原问题的解,那么这种分治法就是可行的。 如果子问题规模还是太大,可反复应用分治手段,使子问题与原问题类型一致而其规模却不断缩小 ,最终使子问题缩小到很容易求出其解。

nk 1

nk 1

Page 3: 第 2 章  分 治 法

2.1 一般方法

分治法的基本思想是将一个规模为 n 的问题分解为 k 个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各子问题的解合并得到原问题的解。 问题: k 如何取? 大好? 小好?

Page 4: 第 2 章  分 治 法

分治法控制流程用 DanC(p,q) 表示处理输入为 A[p:q] 情况的问题。DanC(p,q) global n , A[1:n]; integer m,p,q; // 1pqn if Small(p,q) then return G(p,q); else m=Divide(p,q); // pm<q return Combine(DanC(p,m),DanC(m+1,q)); endifend DanCSmall(p,q) 是一个布尔值函数,用以判断输入规模。如果规模小,则调用 G(p,q) 直接求解,否则用分割函数 Divide(p,q)将输入分成两部分,分别调用原过程求解,并用 Combine合并成原问题的解。

Page 5: 第 2 章  分 治 法

时间复杂性递归方程 如果假定所分成的两个问题的输入规模大致相等,则 DanC 总的计算时间可用下面的递归关系来表示:

其中, T(n) 是输入规模为 n 的 DANDC 时间, g(n) 是对足够小的输入规模能直接计算出答案的时间, f(n)是 COMBINE 的时间。

)()2/(2)(

)(nfnT

ngnT

Page 6: 第 2 章  分 治 法

2.2 二分检索 ( 运用分治策略的典型例子)问题: 输入是一个按非降次序排列的元素表 a1 , a2,… , an ,要求判定某给定元素 x 是否在该表中出现。若是,则找出 x 在表中的位置,并将此下标值赋给变量 j ;若非,则将 j 置成 0 。分析: 设该问题用 I = (n , a1 , a2,… , an , x) 来表示,选取一个下标 k ,得到三个子问题

I1= (k-1 , a1 ,…, ak-1 , x) , I2=(1, ak , x) 、 I3=(n-k , ak+l ,…, an ,

x)

如果 x= ak ,则 j = k ,算法结束; 否则,若 x< ak ,则只需对 Il 求解; 若 x>ak ,只需对 I3 求解;

I2 I3

(I1

) )( ( )…… …….

Page 7: 第 2 章  分 治 法

2.2.1 二分检索算法过程 BINSRCH 有 n+2 个输入: A , n 和 x ,一个输出 j ,用 A[1:n] 来表示 n 个待检索的元素。过程结束时,如果 x 不在表中,则 j = 0 ,否则 A(j) = x 。procedure BINSRCH(A , n , x , j) // 给定一个按非降次序排列的元素数组 A(1 : n) , n≥1 ,判断 x 是否出现。若是,置 j ,使得 x = A(j ) ,若非, j = 0// integer low , high , mid , j , n ; low←1 ; high←n while low≤high do // 只要还有待检查的元素,循环就继续下去 mid← case : x<A(mid) : high←mid-1 : x>A(mid) : low←mid+l : else : j←mid ; return endcase repeat j←0 end BINSRCH 。

high)/2(low

Page 8: 第 2 章  分 治 法

二分检索实例 假定在 A(1 : 9) 中顺序存放着以下九个元素: -

15 , -6 , 0 , 7 , 9 , 23 , 54 , 82 , 101 。检索 x=101 是否在 A 中。第一次执行循环体: mid=5 , A[mid] < x 需要在 A[5]~A[9] 中检索;第二次执行循环体: mid=7 , A[mid] < x 需要在

A[8]~A[9] 中检索;第三次执行循环体: mid=8 , A[mid] < x 需要在

A[9]~A[9] 中检索;第四次执行循环体: mid=9 , A[mid] = x 返回 9 ;

Page 9: 第 2 章  分 治 法

检索的算法执行过程的二分检索树表示

每个内部结点表示一次元素比较,它用圆形结点来表示,圆节点也表示成功的检索,外结点用一个方形结点表示,方节点表示不成功的检索,每一条路径表示一个元素比较序列。 成功检索:从二分检索树可以看到,最好情况要进行 1 次比较,最坏情况要进行 4 次比较,如果 x 等概率取数组中的任一值,成功检索的平均比较次数为 25/9≈2.77 。 不成功检索:为了确定 x 不在 A 中出现,算法要作 3~4 次元素比较。

12

34

57

6 89

Page 10: 第 2 章  分 治 法

二分检索的时间复杂度分析 若 中,则对于一次成功的检索,至多作

k 次比较,对于不成功的检索或者作 k 次比较或者作 k-1 比较。即最坏情况的比较次数是树的深度 k ,最好情况的比较次数是树的深度 k-1 。 每执行一次于 while 循环,待搜索的数组的大小减少一半,因此,在最坏情况下, while 循环执行了 O( logn) 次。循环体内运算需要 O( 1 )时间,因此整个算法在最坏情况下的计算时间复杂性为 O( logn) 顺序搜索需用 O( n )次比较。

)2,2[ 1 kkn

Page 11: 第 2 章  分 治 法

2.3 找最大和最小元素问题:在含有 n 个不同元素的集合中同时找出它的最大和最小元素。 分治策略设计思想:将任一实例 I = (n , A(1) ,…, A(n)) 分成两个实例 :

))(),.....,12/(,2/())2/(),.....,1(,2/(

2/

2

1

nAnAnnInAAnI

nm

1I

MAX1 、 MIN1 MAX2 、 MIN2

{……………. } {…..……….. }2I

MAX MIN

Page 12: 第 2 章  分 治 法

如果 MAX1 和 MIN1 是 I1 中的最大和最小元素, MAX2 和 MIN2 是 I2 中的最大和最小元素, MAX1 和 MAX2 中的大者就是 I 中的最大元素 MAX , MIN1 和 MIN2 中的小者是 I 中的最小元素 MIN 。如果 I 只包含一个元素,则不需要 作任何分割直接就可得到其解。

Page 13: 第 2 章  分 治 法

procedure MAXMIN(I , j , fmax , fmin)

/*A(1 : n) 是含有 n 个元素的数组,参数 i , j 是 整数, 1≤i , j≤n 该过程把 A(i , j) 中的最大和最小元素分别赋给 fmax 和 frain */ integer i , j ; global n , A(1:n) case : i = j : fmax←fmin←A(i) // 只有一个元素 : i = j-1 : if A(i)<A(j) then fmax←A(j) ; fmin←A(i) else fmax←A(i) ; fmin←A(j) // 有两个元素 endif : else : mid← ; // 分成两个子集 call MAXMIN(i , mid , max1 , min1) call MAXMIN(mid+1 , j , max2 , min2) fmax←max(max1 , max2) fmin←min(min1 , min2) endcase end MAXMlN

2/)( ji

Page 14: 第 2 章  分 治 法

例在下述实例上模拟过程 MAXMIN A= (22 ,13 , -5 , -8 , 15 , 60, 17 , 31 , 47) 用一棵树来描述递归调用的轨迹是很清晰的,其中的一个结点表示一次递归调用,每作一次新的调用就增加一个结点。对于这个程序来说,每个结点有四项信息: i , j , fmax , fmin 。 根据数组 A ,可作出如下图所示的树。

1 9 60 - 8, , ,

1 5 22 - 8, , , 6 9 60 17, , ,

1 3 22 - 5, , , 4 5 15 - 8, , , 6 7 60 17, , , 8 9 47 31, , ,

1 2 22 13, , , 3 3 - 5 - 5, , ,

(22 , 13 , -5 , -8 , 15 , 60, 17 , 31 , 47)

22 , 13 , -5 , -8 , 15 60, 17 , 31 , 47

22 , 13 , -5 ,

22 , 13

Page 15: 第 2 章  分 治 法

MAXMIN 的时间复杂性分析 MAXMIN 需要的元素比较数是多少呢 ? 如果用 T(n) 表示这个数,则所导出的递归关系式是:

2)2/()2/(10

)(nTnT

nT

当 n 是 2 的幂时,即对于某个正整数 k , n=2k ,有 T(n) : 2T(n/2)+2 = 2(2T(n/4)+2)+2 =4T(n/4)+4+2…… =2 k-1 T(2)+(21+22+…2K-1) =n/2+n-2 =3n/2-2

n=1

n=2

n>2

注意 : 当 n 是 2 的幂时, 3n/2-2 是最好,平均及最坏情况的比较数和直接算法的比较 数 2n-2 相比,它少了25%。

Page 16: 第 2 章  分 治 法

2.4 归并分类 ( 归并排序) 归并分类用分治策略实现对 n 个元素进行擀序的算法。 基本思想是:当 n=1 时终止排序,否则将待排序元素分成大小大致相同的两个子集合,分别对两子集合进行排序,最终将好序的子集合合并成为所要求的排好序的集合。

Page 17: 第 2 章  分 治 法

归并分类问题描述 问题: 给定一个含有 n 个元素的集合,把它们按一定的次序分类 ( 假定按非降次序 ) 。 分治策略设计思想:将任一实例I = (n , A(1) ,…, A(n)) 分成两个这样的实例:I1 = ( , A(1) ,…, A( )) 和I2 = (n- , A( 十 1) ,…, A(n)) 。 分别对每个集合单独分类,然后将已分类的两个序列归并成一个含 n 个元素的分好类的序列。这种思想是典型的分治设计思想,归并分类也叫做分治合并排序。

2/n

I1 I2

I

2/n 2/n 2/n

Page 18: 第 2 章  分 治 法

归并两个已分类的集合procedure MERGESORT(low , high) //A(low ; high) 是一个全程数组,它含有 high-low+1≥0 个待分类的元素 // integer low , high ; if low<high ; then mid← , // 求这个集合的分割点 // call MERGESORT(low , mid) // 将一个子集合分类 // call MERGESORT(mid+1 , high) // 将另一个子集合分类 call MERGE(low , mid , high) // 归并两个已分类的子集合 // endif end MERGESORT

2/n

Page 19: 第 2 章  分 治 法

integer h , i , j , k ; h←low ; i←low ; j←mid+1 ; while h≤mid and j≤high do // 当两个集合都没取尽时 // if A(h)≤A(j) then B(i) ←A(h) ; h←h+1 else B(i) ←A(j) ; j←j+1 endif i←i+1 repeat if h>mid then for k←j to high do // 处理剩余的元素 // B(i) ←A(k) ; i←i+1 repeat else for k←h to mid do B(i) ←A(k) ; i←i+1 repeat endif 将已归并的集合复制到 A end MERGE

合并算法 MERGEprocedure MERGE(low , mid , high)

//A(low : high)是一个全程数组 // //辅助数组B(low ; high)//

Page 20: 第 2 章  分 治 法

归并分类算法时间复杂性分析 用 T(n) 表示归并排序所用的时间,并假定合并过程所用时间: cn ,其中 c 是一个正数,则有

其中,是一个常数。若 n 是 2 的方幂: ,直接推导可得:

对于一般的整数 n ,我们可以假定 ,于是, ,因此

1)2/(2

1)( ncnnTnanT

kn 2

ncnankcnT

cnnTcncnnTnT

k

log)1(2

2)4/(4)2/)4/(2(2)(

122 kk n)2()( 1 kTnT )log()( nnOnT

Page 21: 第 2 章  分 治 法

改进的归并分类算法 归并分类算法还存在一些不足,从而限制了分类效率的进一步提高。从前面 MERGESORT 过程可以看出,每当集合被分成只含二个元素的子集合,还需要使用二次递归调用将这子集合分成单个元素的集合。表明该算法执行到将集合分成含元素相当少的子集合,很多时间不是用在实际的分类而是消耗在处理递归上。而插入分类算法虽然复杂度为 O( n2),但当 n 很小(如 16 时)却能极快地工作,因此将其作为归并分类算法中处理小规模集合情况的子过程,能够进一步提高归并分类的效率。 算法 2.10 P50

Page 22: 第 2 章  分 治 法

2.5 快速分类 由著名的计算机科学家霍尔 (C. A. R. H

oare) 给出的快速分类算法也是根据分治策略设计的一种高效率的分类算法。它虽然也是把文件 A(1 :n) 分成两个子文件,但与归并分类算法有所不同: 在被分成的两个子文件以后不再需要归并。于是,被分成的两个子文件至少必须满足一子文件中的所有元素都小于或等于另一子文件的任何一个元素。这是通过重新整理 A(1 : n) 中元素的排列顺序来达到的。I1

I2

partitionelement

I1

Page 23: 第 2 章  分 治 法

选取 A 的某个元素,譬如说 t = A(s) ,然后将其它元素重新排列,使 A(1 : n) 中所有在 t 以前出现的元素都小于或等于 t ,而所有在 t 后面出现的元素都大于或等于 t 。文件的这种重新整理叫做划分 (partitioning) ,元素 t 称为划分元素 (partitionelement) 。因此,所谓快速分类就是通过反复对产生的文件进行划分来实现的。

I1

partitionelement

快速分类的分治策略:

Page 24: 第 2 章  分 治 法

快速排序的步骤 : 对于输入的子数组 A[p:r],快速排序按以下三个步骤进行排序 : (1) 分解 (Divide): 以 A[p] 为基准元素将 A[p:q]划分成 3 段: A[p : j-1],A[j] 和 A[j+1 : q], 使得 A

[p : j-1] 中任何一个元素都小于等于 A[j] , A[j+1 :q] 中任何一个元素,下标 j 在划分过程中确定。

( 2 )递归求解( Conquer):通过快速排序算法分别对 A[p : j-1] 和 A[j+1 : q] 进行排序 ( 3 )合并(Merge) :由于 A[p : j-1] 和 A[j+1 :

q] 的排序都是就地进行的,所以对 A[p : j-1] 和A[j+1 : q] 排好序后不需任何操作 A[p:q] 就已排好序。(实际不需合并)

Page 25: 第 2 章  分 治 法

QuickSort(p,q) // 将数组 A[1:n] 中的元素 A[p], A[p+1], , A[q] 按递增方式排列, 并假定 A[n+1] 是一个确定的且大于 A[1:n] 中所有的数。 //

int p,q; global n, A[1:n]; if p<q then j=Partition(p,q); // 划分后 j 成为划分元素的位置 QuickSort(p,j-1); QuickSort(j+1,q); endif end QuickSort

快速分类算法

Page 26: 第 2 章  分 治 法

integer m , p , I , j ; global A(m : p) v←A(m) ; i←m ;j ←p+1 //A(m) 是划分元素 // loop loop i←i+1 until A(i)≥v repeat //i由左向右移 // loop j←j-1 until A(j)≤v repeat //p由右向左移 // if i<j then call INTERCHANGE(A(i) , A(j)) //A(i) 和 A(p)换位 // else exit endif repeat A(m) ←A(j) ; A(j) ←v //划分元素在位置 p// return j; End PARTITION

m p

m i,j

procedure PARTITION(m , p) //退出过程时,带着划分元素所在的下标位置。且已对 A[m:p] 进行分段 // 。

Page 27: 第 2 章  分 治 法

PARTITION 的主要功能

PARTITION 对 A[m:p] 进行划分时,以元素 x=A[m] 作为划分的基准,分别从左、右两端开始,扩展两个区域 A[m:i] 和 A[j:p], 使得 A[m:i] 中元素小于或等于 v, 而A[j:p] 中元素大于或等于 v 。初始时: i=m, 且 j=p+1

PARTITION 的主要功能是将小于基准元素 a[m] 的元素放在原数组的左半部分。而将大于基准元素的元素放在原数组的右半部分。

Page 28: 第 2 章  分 治 法

快速分类时间复杂性分析对于输入对列 A[m:p],PARTITION(m , p) 的计算时间显然是 O( p-m-1) 。快速排序的运行时间与划分是否对称有关,其 最坏情况 : 发生在划分过程产生两个区域分别包含 n-1 个元素和 1 个元素 (另一个为空)。由于 PARTITION的计算时间为 O( n), 所以如果算法 PARTITION 的每一步都出现这种极不对称的划分,则其计算时间复杂性 T( n)满足:

解此递归方程可得 T( n)=O(n2)

1)()1(1)1(

)(nnOnTnO

nT

Page 29: 第 2 章  分 治 法

快速分类时间复杂性分析最好情况下,每次划分所取的基准都愉好为中值,即每次都产生两个大小为 n/2 的区域,此时, PARTITION 的计算时间 T( n)满足:

其解为 T(n)=O(nlogn) 。可以证明:快速排序在平均情况下的时间复杂性也是 O(nl

ogn) ,这在基于比较的排序算法中算是快速的,快速排序因此得名。

1)()2/(21)1(

)(nnOnTnO

nT

Page 30: 第 2 章  分 治 法

QuickSort 的平均时间复杂性分析两个假设①参加分类的 n 个元素各不相同;②PARTITION 中的划分元素 v 是随机选取的,

A[m, p] 中各个元素成为划分元素的概率是相等的,即划分元素的下标 k 等概率取 1~n 。

Page 31: 第 2 章  分 治 法

设 QUICKSORT 的元素平均比较次数为 CA(n) ,在上述假设条件下,两个子集的元素个数分别为 k-1, 和 n-k ,两个子集的元素平均比较次数分别为 CA (k-1) 和 CA (n-k) ,由此得递归关系式:))()1((11)(

1knCkC

nnnC AA

nkA

其中, n+1 是 Partition 第一次被调用时所需要的元素比较次数,CA (0)= CA (1)=0 。两端乘以 n 得 (4.4) :

))1()1()0((2)1()( nCCCnnnnC AAAA

用 n-1替换上式中的 n ,得 (4.5) :))2()1()0((2)1()1()1( nCCCnnnCn AAAA

再用 (4.4)减去 (4.5)式得 (4.6) :

)1/(2/)1()1/()( nnnCnnC AA

Page 32: 第 2 章  分 治 法

递归推导 (4.6)式,并注意到 0)1()0( AA CC

1

2

1

2

)/2()1/()(

/2)1/()(

1...)1/(2/2)1/(2)1/()(2/21/)0(2/)1(

......)1/(2)2/()3()1/()2(

/2)1/()2(/)1()1/(2/)1()1/()(

n

A

n

iA

A

AA

AA

AA

AA

dxxnnC

innC

nnnnnCCC

nnnCnnCnnnCnnC

nnnCnnC

)log()1ln()1(2)( nnOnnnCA 得

Page 33: 第 2 章  分 治 法

2.6 选择问题 问题描述:给定线性集中 n 个元素和一个整数

k, 要求找出这 n 个元素中第 k 小的元素,即如果将这 n 个元素依其线性序排列时,排在第 k个位置的元素即为我们要找的元素。 当 k=1 时,即找最小元素;当 k=n 时,即找最大元素;当 k=(n+1)/2 时,称为找中位数。

Page 34: 第 2 章  分 治 法

选择问题算法 上述 Partition 算法也可用来求选择问题的有效解。如果划分元素 v测定在 A( j )的位置上,则有 j-1 个元素小于或等于 A(j), 且有 n-j 个元素大于或等于 A(j) 。因此,若 k<j, 则第 k 小元素在 A( 1 : j-1) 中,再对之进一步划分。 若 k=j, 则 A(j) 就是第 k 小元素 若 k>j, 则第 k 小元素在 A( j+1:n) 中,再对之进一步划分。

Page 35: 第 2 章  分 治 法

选择问题算法 - 算法 2.15 找第 k 小元素procedure SELECT( A,n,k) integer n,k,m,r,j m←1 ; r←n; loop j= partition(m,r) case : k=j: return : K<j: r ←j :else: m ←j+1 endcase repeat End SELECT

Page 36: 第 2 章  分 治 法

SELECT 的时间复杂度分析 类似于快速排序中对 PARTITION 的分析,

SELECT 的最坏情况时间复杂度为 O(n2)

但 SELECT 的平均计算时间只是 O( n)(证明略)

Page 37: 第 2 章  分 治 法

最坏情况时间是 O(n) 的选择算法通过精细地挑选划分元素 v, 可以得到一个最坏情况时间复杂度是 O(n) 的选择算法! 如果能在线性时间内找到一个划分基准,使得按这个基准所划分出的两个子数组都至少为原数组的,那么在最坏情况下用 O(n) 时间就可以完成选择任务。 用二次取中法可以选出这样的划分元素。

)10( 是某个正常数倍

Page 38: 第 2 章  分 治 法

划分基准的选择方法 ( 1 )将 n 个元素输入元素分成 n/5 个组 , 每组

5 个元素 (忽略剩余元素 ) 。将每组元素排好序(插入法),并取出每组的中位数,共 n/5 个。(说明: n/5 这里指的 n/5 的向上取整 ; 可将 5改为大于 1 的任意正整数 r) ( 2 )递归调用选择算法来找出 n/5 个元素的中位数。若 n/5 是偶数,就找它的两个中位数中较大的一个。然后以这个元素作为划分基准。 图 2.7 选择划分基准的示意图 .P60

Page 39: 第 2 章  分 治 法

二次取中的选择算法的直观描述procedure SELECT2( A,k,n) // 在 A 中找第 k 小元素 1. 若 n<=r, 则用插入法对 A 分类并返回第 k 小元素 . 2.把 A 分成大小为 r 的一系列子集 ,忽略剩余元素 . 3. 将它们各自排好序 , 并返回各子集中位数 mi, 设 M={m

1,m2,…,m n/r } 4.v← SELECT2(M,n/r/2,n/r) 5. 用 PARTITION划分 A,v 作为划分元素 . 6. 设 V 在位置 j 7. case : k=j: return(v) : K<j: 设 L 是 A(1:j-1) 中元素的集合 return(SELECT2(L,k,j-1)) :else: 设 R 是 A(j+1:n) 中元素的集合 return(SELECT2(R,k-j,n-j)) endcase End SELECT2 注意 : 一般情况下 ,r=5

Page 40: 第 2 章  分 治 法

SELECT2 的复杂度分析 -- 假设 A 中的元素互不相同。

LH

H

LH

H

vH

H

LH

H

LH

H

5 元素的排序各组

TT

S

TT

S

TT

S

TT

S

TT

显然:标注为 T 和 S 的一定不在集合 R 中,标注为 H 和 L 的一定不在集合 L 中所以在 45 个元素中,递归调用最多对 45-14-1=30 个元素进行。即每个递归子问题的大小最多是原问题的 75%(实际大约 70% )

Page 41: 第 2 章  分 治 法

时间复杂度函数 第 1步 : 在 O( 1 )内完成。 第 2 、 3 、 5 和 6 步: O( n) 第 4步: T(n/5) 第 6步: T( 3n/4 )因此: cnnTnTnT )5/3()5/()(