分治策略1
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
复杂度分析
O(1) n 1 T (n) 2T (n / 2) O(n) n 1
T(n)=O(nlogn) 渐进意义下的最优 算法
合并排序
算法mergeSort的递归过程可以消去。
初始序列 [49] [38] [65] [97] [76] [13] [27]
第一步
[38 49]
问百度文库S1
问题S2
……
问题Si 子问题求 解
……
问题Sn
S1的解
S2的解
……
Si的解
……
Sn的解
子集解的合并
问题 S的解 S
2 分治法的适用条件
分治法所能解决的问题一般具有以下几个特征: 该问题的规模缩小到一定的程度就可以容易地解决; 该问题可以分解为若干个规模较小的相同问题,即该 问题具有最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的 解; 该问题所分解出的各个子问题是相互独立的,即子问 题之间不包含公共的子问题。 这条特征涉及到分治法的效率,如果各子问题是不 因为问题的计算复杂性一般是随着问题规模的增加 能否利用分治法完全取决于问题是否具有这条特征, 这条特征是应用分治法的前提,它也是大多数问题 独立的,则分治法要做许多不必要的工作,重复地 而增加,因此大部分问题满足这个特征。 可以满足的,此特征反映了递归思想的应用 如果具备了前两条特征,而不具备第三条特征,则 解公共的子问题,此时虽然也可用分治法,但一般 可以考虑 贪心算法 用 动态规划 较好。或动态规划。
4 典型例子——二分搜索技术
不同于现实中对问题(或工作)的分解,可能会考虑问题 (或工作)的重点、难点、承担人员的能力等来进行问题的分
解和分配。在算法设计中每次一个问题分解成的子问题个数一 般是固定的,每个子问题的规模也是平均分配的。当每次都将 问题分解为原问题规模的一半时,称为二分法。二分法是分治 法较常用的分解策略,数据结构课程中的折半查找、归并排序 等算法都是采用此策略实现的。
//输入:两个有序数组B[0..p-1]和C[0..q-1]
//输出:非降序列数组A-0..p+q-1] i0; j0; k0; while (i<p and j<q do){
if (n>1){
copy A[0.. [n/2]-1] to B[0..[n/2]-1] ; copy A[[n/2]..n-1] to C[0..[n/2]-1]; Mergesort(B[0..[n/2]-1]);
分治法在每一层递归上由三个步骤组成:
(1) 划分(divide):将原问题分解为若干规模较小、 相互独
立、 与原问题形式相同的子问题。
(2) 解决(conquer): 若子问题规模较小,则直接求解;否
则递归求解各子问题。
(3) 合并(combine): 将各子问题的解合并为原问题的解。
分治思想
问题的分解 问题S
一、分治策略的基本思想
1 基本思想
对于一个规模为n的问题,若该问题可以容易地解决(比如说
规模 n较小) ,则直接解决,否则将其分解为 k 个规模较小的子问
题,这些子问题互相独立且与原问题形式相同,递归地解这些子
问题, 然后将各子问题的解合并,得到原问题的解。这种算法 设计策略叫做分治法(divide and conquer)。
if (B[i] ≤ C[j]) {
A[k]B[i];ii+1;} else{ A[k]C[j];jj+1;} kk+1; } if (i=p) copy C[j..q-1] to A[k...p+q-1] else copy B[j..p-1] to A[k...p+q-1]
Mergesort(C[0..[n/2]-1]);
二分搜索技术
给定已按升序排好序的n个元素a[0:n-1],现要在这n个元素 中找出一特定元素x。 算法复杂度分析: 据此容易设计出二分搜索算法: 每执行一次算法的 public static int binarySearch(int [] a, int x, int n) while循环, 待搜索 { // 在 a[0] <= a[1] <= ... <= a[n-1] 中搜索 x 数组的大小减少一半。 // 找到x返回其在数组中的位臵,否则返回-1 因此,在最坏情况下, int left = 0; int right = n - 1; while循环被执行了 while (left <= right) { int middle = (left + right)/2; O(log2n) 次。循环体 if (x == a[middle]) return middle; 内运算需要O(1) 时间, if (x > a[middle]) left = middle + 1; 因此整个算法在最坏 else right = middle - 1; } 情况下的计算时间复 return -1; // 未找到x 杂性为O(log2n) 。 }
第三章 分治算法
一、 分治算法基本思想
二、 典型实例
三、 分治算法的分析技术
四、 难解问题
问题:找出伪币
给你一个装有1 6枚硬币的袋子。1 6枚硬币中有 一个是伪造的,并且那个伪造的硬币比真的硬币 要轻一些。你的任务是找出这枚伪造的硬币。 为了帮助你完成这一任务,将提供一台可用来比 较两组硬币重量的仪器,比如天平。利用这台仪 器,可以知道两组硬币的重量是否相同。
二分搜索技术
给定已按升序排好序的n个元素a[0:n-1],现要在这n个元素 中找出一特定元素x。 分析: 该问题的规模缩小到一定的程度就可以容易地解决; 该问题可以分解为若干个规模较小的相同问题; 分解出的子问题的解可以合并为原问题的解; 分解出的各个子问题是相互独立的。 分析: 比较 x 和a即只有一个元素,则只要比较这个元素和 的中间元素a[mid],若x=a[mid],则x在L中 分析: 如果 n=1 x 的位臵就是 mid ;如果x<a[mid],由于a是递增排序的,因 就可以确定 x是否在表中。因此这个问题满足分治法的第一 此假如 x在a中的话,x必然排在a[mid]的前面,所以我们只 分析: 很显然此问题分解出的子问题相互独立,即在 a[i]的前 个适用条件 要在a[mid]的前面查找 x即可;如果x>a[i],同理我们只要在 面或后面查找 x是独立的子问题,因此满足分治法的第四个适 a[mid]的后面查找x即可。无论是在前面还是后面查找x,其 用条件。 方法都和在a中查找x一样,只不过是查找的规模缩小了。 这就说明了此问题满足分治法的第二个和第三个适用条件。
else mDIVIDE(p,q); //p≤m≤q// return(COMBINE(DANDC(p,m),DANDC(m+1,q)));
将两个子问题的解 合成原问题
分割函数
DANDC的计算时间
倘若所分成的两个子问题的输入规模大致相等, 则DANDC的计算时间可表示为:
g(n) n足够小
否则
void MergeSort(Type a[], int left, int right) { if (left<right) {//至少有2个元素 int i=(left+right)/2; //取中点 mergeSort(a, left, i); mergeSort(a, i+1, right); merge(a, b, left, i, right); //合并到数组b copy(a, b, left, right); //复制回数组a } }
原始问题 的规模是n
子问题1的 规模是n/2
子问题2的 规模是n/2
子问题2的解
子问题2的解
原始问题的解
分治法的抽象化控制
算法 DANDC(int p,int q) 判断输入规模 int m,p,q; //1≤p≤q≤n// q-p+1是否足够的小 if SMALL(p,q) return(G(p,q)); 求解该规模问题解的函数
方法1
任意取1枚硬币,与其他硬币进行比较,若发现 轻者,这那枚为伪币。最多可能有15次比较。
方法2
将硬币分为8组,每组2个,每组比较一次,若发 现轻的,则为伪币。最多可能有8次比较。
方法3
分析
上述三种方法,分别需要比较15次,8次,4次, 那么形成比较次数差异的根本原因在哪里? 方法1:每枚硬币都至少进行了一次比较,而 有一枚硬币进行了15次比较 方法2:每一枚硬币只进行了一次比较 方法3:将硬币分为两组后一次比较可以将 硬币的范围缩小到了原来的一半,这样充分 地利用了只有1枚伪币的基本性质。
[65 97]
[13 76]
[27]
第二步
第三步
[38 49 65 97]
[13 27 76]
[13 27 38 49 65
76 97]
合并排序
I=(n, A[0…n-1]) I1=(n-[n/2], A[0…[n/2]-1]) ...... ...... I2=(n-[n/2]-1, A[[n/2]-1…n-1]) ...... Ij=(1,A[m]) ...... Ik=(1,A[n])
分治策略的解题思路
if 问题不可分then begin 直接求解; 返回问题的解; end else begin 对原问题进行分治; 递归对每一个分治的部分求解 归并整个问题,得出全问题的解; end;
3 分治法的基本步骤
divide-and-conquer(P) { if ( | P | <= n0) adhoc(P); //解决小规模的问题 divide P into smaller subinstances P1,P2,...,Pk;//分解问题 for (i=1,i<=k,i++) yi=divide-and-conquer(Pi); //递归的解各子问题 return merge(y1,...,yk); //将各子问题的解合并为原问题的解 }
二分搜索技术
算法复杂度分析: 二分搜索算法在最坏情况下的计算时间复杂性 为O(log2n) 。
复杂度分析
n 1 O(1) T ( n) T (n / 2) b n 1 T(n)= O(log2n)
二、分治算法的经典实例
合合并排序
1.合并排序
基本思想:将待排序元素分成大小大致相同的2个子集合,分 别对2个子集合进行排序,最终将排好序的子集合合并成为所 要求的排好序的集合。
合并排序
8 3 2 9 7 1 5 4
8 3 2 9 8 3 8 3 8 3 2 2 9 2 9 9 7 1 7 7 1 1 5 4 5 7 1 5 4 5 4 4
2 3 8 9
1 2 3 4 5 7 8 9
1 4 5 7
合并排序
基本思想:将待排序元素分成大小大致相同的2个子集合,分 别对2个子集合进行排序,最终将排好序的子集合合并成为所 要求的排好序的集合。
T(n)=
2T(n/2)+f(n)
说明:T(n)式输入规模为n的DANDC的计算时间 g(n)是对足够小的输入规模能直接计算出答案的时间 f(n)是COMBINE的计算时间
人们从大量实践中发现,在用分治法设计算法时, 最好使子问题的规模大致相同。即将一个问题分 成大小相等的k个子问题的处理方法是行之有效的。 这种使子问题规模大致相等的做法是出自一种平 衡(balancing)子问题的思想,它几乎总是比子问 题规模不等的做法要好。
B[1]
...
比较大小
B[p-1]
比较大小
小 值
……
剩余已排序元素
数组A B[0] C[0]
合并排序算法
算法 Merge(B[0..p-1],C[0..q-1]),A[0..p+q-1]) 算法 Mergesort(A[0...n-1]) //递归调用Mergesort来对数组A排序 //输入:可排序数组A[0..n-1] //输出:非降序列数组A[0..n-1] //将两个有序数组合并成一个有序数组
Ih=(1,A[0])
Ii=(1,A[1])
Ihi=(2,A[0...1]) ...... MERGE I=(n,A(1),…A(n))
Ijk=(2,A[m...n]) ......
合并函数MERGE的实现
合并函数MERGE的实现思想
已排序序列B
B[0]
小 值
已排序序列C
C[0] C[1] … C[q-1]