第3章 分治算法
分治算法

贪心算法贪心算法贪来自算法解题思路:对每个节目的结束时间升序排序,然后比较 后一个节目的开始时间是否晚于前一个可以看完的 节目(数据 t )打的结束时间,是则数目加一,将 t 赋值为此节目,不是则继续判断下一个节目,默 认将第一个节目看做第一个可以看完的节目。
分治算法
分治算法
• 基本思想
– 当我们求解某些问题时,由于这些问题要处理 的数据相当多,或求解过程相当复杂,使得直 接求解法在时间上相当长,或者根本无法直接 求出。对于这类问题,我们往往先把它分解成 几个子问题,找到求出这几个子问题的解法后 ,再找到合适的方法,把它们组合成求整个问 题的解法。如果这些子问题还较大,难以解决 ,可以再把它们分成几个更小的子问题,以此 类推,直至可以直接求出解为止。
分治算法
• 应用实例
– 1. 找出伪币
• 方案 1 两两比较: • 比较硬币 1 与硬币 2 的重量。假如硬币 1 比硬币 2 轻,则硬币 1 是伪造的;假如硬币 2 比硬币 1 轻, 则硬币 2 是伪造的。这样就完成了任务。假如两硬 币重量相等,则比较硬币 3 和硬币 4 。同样,假如 有一个硬币轻一些,则寻找伪币的任务完成。假如 两硬币重量相等,则继续比较硬币 5 和硬币 6 。按 照这种方式,可以最多通过 8 次比较来判断伪币的 存在并找出这一伪币。
max=13 min=-13
C1 -13 13 low=0 high=1 max1=13 min1=-13
C2 9 -5 low=2 high=3 max2=9 min2=-5
分治算法
B2 7 23 0 low=4 high=7 15 mid=5 max=23
min=7
C3 7 23 low=4 high=5 max1=23 min1=7
分治算法

65 97
13 76
38 49 65 97
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归 调用
49 38 65 97 76 13 27
38 49
65 97
13 76
27
38 49 65 97
题的解,自底向上逐步求出原来问题的解。
T(n)
=
n
递归的概念
由分治法产生的子问题往往是原问题的较小模式,这 就为使用递归技术提供了方便。在这种情况下,反复 应用分治手段,可以使子问题与原问题类型一致而其 规模却不断缩小,最终使子问题缩小到很容易直接求 出其解。这自然导致递归过程的产生。
直接或间接地调用自身的算法称为递归算法。用函数 自身给出定义的函数称为递归函数。
黑盒划分典型问题—合并排序
【例5】合并排序
任务描述:任意给定一包含n个整数的集合,把n个整数按升序排列。 输入:每测试用例包括两行,第一行输入整数个数,第二行输入n个整 数,数与数之间用空格隔开。最后一行包含-1,表示输入结束。 输出:每组测试数据的结果输出占一行,输出按升序排列的n个整数。 样例输入:
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归调用 自然合并排序
49 38 65 97 76 13 27
49
38 65 97
76
13 27
38 49 65 97
黑盒划分典型问题—逆序对问题
分治算法知识点总结

分治算法知识点总结一、基本概念分治算法是一种递归的算法,其基本思想就是将原问题分解成多个相互独立的子问题,然后分别解决这些子问题,最后将子问题的解合并得到原问题的解。
分治算法的核心思想可以用一句话概括:分而治之,分即是将原问题分解成若干个规模较小的子问题,治即是解决这些子问题,然后将子问题的解合并起来得到原问题的解。
分治算法通常包括三个步骤:(1)分解:将原问题分解成若干个规模较小的子问题;(2)解决:递归地解决这些子问题;(3)合并:将子问题的解合并起来得到原问题的解。
分治算法的典型特征包括递归和合并。
递归指的是将原问题分解成若干个规模较小的子问题,然后递归地解决这些子问题;合并指的是将子问题的解合并得到原问题的解。
通常来说,分治算法的递归实现方式很容易编写,但有时可能会面临大量的重复计算,因此需要合并操作来避免这种情况。
二、原理分治算法的原理可以通过一个简单的例子来说明。
我们以计算数组中的最大值为例,具体的步骤如下:(1)分解:将数组分解成两个规模相等的子数组;(2)解决:递归地在这两个子数组中分别找到最大值;(3)合并:比较这两个子数组的最大值,得到原数组的最大值。
从这个例子可以看出,分治算法将原问题分解成两个子问题:分别在左边子数组和右边子数组中找到最大值,然后将这两个子问题的解合并起来得到原数组的最大值。
这种将问题分解成若干个规模较小的子问题,然后合并子问题的解得到原问题的解的方法正是分治算法的核心原理。
分治算法的优势在于它可以将原问题分解成多个规模较小的子问题,然后并行地解决这些子问题,最后合并子问题的解得到原问题的解。
这种并行的设计思路使得分治算法非常适合于并行计算,能够有效地提高计算效率。
三、应用分治算法在计算机科学领域有着广泛的应用,包括排序、搜索、图论、动态规划等多个方面。
下面我们将以排序算法和搜索算法为例,来介绍分治算法在实际应用中的具体情况。
1. 排序算法排序算法是计算机科学领域中一个重要的问题,分治算法在排序算法中有着广泛的应用。
算法设计与分析第三章 分治法

X15:X16
X15 X16
North China Electric Power University
§2 二分搜索技术
问题描述:给定已排序好的 个元素 个元素a[1:n],现在要在这 个元素 现在要在这n个元素 问题描述:给定已排序好的n个元素 现在要在这 中找出一特定元素x。 中找出一特定元素 。 二分搜索法的基本思想: 个元素分成大致相同的两半, 二分搜索法的基本思想:将n个元素分成大致相同的两半,取 个元素分成大致相同的两半 a[n/2]与x做比较,如果 做比较, 与 做比较 如果x=a[n/2]则,则找到 ,算法终止;如果 则 则找到x,算法终止; x≤a[n/2],则只要在 的左半部继续搜索;如果 的左半部继续搜索; ,则只要在a的左半部继续搜索 如果x>a[n/2],则 , 只要在a的右半部继续搜索 的右半部继续搜索。 只要在 的右半部继续搜索。 template <class Type> int Binary_Search(Type a[],int left ,int right,const Type &x) { if (left>right) return(-1); else { m=(left+right)/2; if (x==a[m]) then return(m) ; else if ( x>a[m]) return(Binary_Search(a,m+1,right,x)); else return(Binary_Search(a,left,m-1,x)); } }
分治法所能解决的问题一般具有以下几个特征(适用条件) 分治法所能解决的问题一般具有以下几个特征(适用条件)
1. 该问题的规模缩小到一定的程度就可以容易地解决; 该问题的规模缩小到一定的程度就可以容易地解决; 该问题可以分解为若干个规模较小的相同问题; 2. 该问题可以分解为若干个规模较小的相同问题;即该问题具 有最优子结构性质; 有最优子结构性质; 利用该问题分解出的子问题的解可以合并为该问题的解; 3. 利用该问题分解出的子问题的解可以合并为该问题的解; 该问题所分解出的各个子问题是相互独立的, 4. 该问题所分解出的各个子问题是相互独立的,即子问题之间 不包含公共的子问题。 不包含公共的子问题。
第3章 分治法

间上界是n-1
void MergePass(int a[],int length,int n) //一趟二路归并排序 { int i;
for (i=0;i+2*length-1<n;i=i+2*length) //归并length长的两相邻子表 Merge(a,i,i+length-1,i+2*length-1);
1. 自底向上的二路归并排序算法
例如,对于{2,5,1,7,10,6,9,4,3,8}序列,其排序过程 如下图所示,图中方括号内是一个有序子序列。
2,5, 1,7,10,6, 9,4, 3,8 底
2,5 1,7 6,10 4,9 3,8
1,2,5,7 4,6,9,10 3,8
1,2,4,5,6,7,9,10 3,8 顶
divide-and-conquer(P)
{ if |P|≤n0 return adhoc(P);
//adhoc(P)是基本子算法,用于 直接解决小规模问题P
将P分解为较小的子问题 P1,P2,…,Pk;
for(i=1;i<=k;i++)
//循环处理k次
yi=divide-and-conquer(Pi); //递归解决Pi return merge(y1,y2,…,yk); //合并子问题
else
//将第2子表中的元素放入tmpa中
{ tmpa[k]=a[j]; j++; k++; }
while (i<=mid)
//将第1子表余下部分复制到tmpa
分治算法的原理

分治算法的原理分治算法是一种将问题分解为更小的子问题,然后解决子问题并将它们的解合并起来得到原问题解的算法。
它的基本思想是将一个复杂的问题划分为多个规模较小但解法相同或相似的子问题,然后对这些子问题进行独立求解,最后将子问题的解合并起来得到原问题的解。
分治算法的步骤通常包括三个阶段:分解、解决和合并。
首先,分解阶段将原问题划分为较小的子问题。
这个步骤通常需要进行递归操作,即将问题规模不断地缩小,直到达到一个基本情况,即问题可以直接解决。
其次,解决阶段对每个子问题进行独立求解。
通常,这个阶段利用递归来解决子问题,递归的结束条件是当子问题可以直接解决时,即达到了基本情况。
最后,在合并阶段,将子问题的解合并起来得到原问题的解。
这个阶段通常需要将子问题的解进行组合、排序或者其他操作,以得到最终的解。
分治算法的优势在于它能够将一个复杂的问题分解为更小的子问题,使得问题的解决过程更加清晰、简明。
并且,分治算法通常能够充分利用多核处理器的并行计算能力,提高算法的执行效率。
分治算法常用于解决诸如排序、查找、图形处理等问题。
下面以一个经典的示例问题来说明分治算法的应用。
示例问题:求解给定数组中的最大值和最小值。
1. 分解阶段:将原问题划分为若干个子问题。
可以将数组划分为两个子数组,然后分别求解两个子数组的最大值和最小值。
2. 解决阶段:对每个子问题进行独立求解。
通过递归,可以将数组不断地划分为更小的子数组,直到达到基本情况,即子数组只包含一个元素,此时最大值和最小值均为该元素。
3. 合并阶段:将子问题的解合并起来得到原问题的解。
对于划分得到的两个子数组的最大值和最小值,可以比较它们的最大值和最小值,得到整个数组的最大值和最小值。
通过示例问题,可以看到分治算法将一个复杂的求解过程分解为两个简单的子问题求解过程。
这样的分解过程使得问题的求解过程更加清晰、简洁,并且能够充分利用递归和并行计算的优势。
在实际应用中,分治算法还有很多应用,例如快速排序、归并排序、二分查找等。
分治算法总结

分治算法总结分治算法是一种将问题分解成更小的子问题并逐个解决的算法策略。
它通常用于解决具有重叠子问题和可分解性质的问题,能够提高问题的解决效率。
本文将对分治算法进行总结,介绍其基本思想、应用领域和解决问题的步骤。
一、基本思想分治算法的基本思想是将一个复杂的问题分解成多个简单的子问题,然后逐个解决这些子问题,并将其合并得到原问题的解。
分治算法通常采用递归的方式来实现,具体步骤如下:1. 分解:将原问题划分成多个规模更小的子问题;2. 解决:递归地求解各个子问题;3. 合并:将子问题的解合并得到原问题的解。
二、应用领域分治算法在许多领域得到了广泛的应用,以下是一些常见的应用场景:1. 排序算法:如快速排序和归并排序,它们都是基于分治思想进行设计的;2. 搜索算法:如二分查找算法,也可以看作是一种分治算法;3. 图算法:如最大子数组和、最短路径等问题都可以使用分治算法进行求解;4. 数据压缩:如Huffman编码算法,也是一种分治算法;5. 多项式乘法:将多项式乘法问题分解成更小的子问题,并通过递归求解得到最终结果。
三、解决问题的步骤使用分治算法解决问题的一般步骤如下:1. 分解:将原问题划分成多个规模更小的子问题;2. 解决:递归地求解各个子问题;3. 合并:将子问题的解合并得到原问题的解。
具体到每个子问题的求解过程,通常可以分为以下几个步骤:1. 边界条件判断:当问题的规模足够小,可以直接求解时,不再进行分解,直接返回结果;2. 分解子问题:将原问题划分成多个规模更小的子问题,通常可以通过将原问题划分成两个或多个规模相同或相似的子问题;3. 递归求解:对每个子问题进行递归求解,直到问题的规模足够小,可以直接求解;4. 合并子问题的解:将子问题的解合并得到原问题的解,通常可以通过简单的合并操作实现。
四、优缺点分析分治算法具有以下优点:1. 可以高效地解决具有重叠子问题和可分解性质的问题;2. 通过将问题划分成多个子问题,可以提高问题的解决效率;3. 适用范围广,可以应用于许多领域。
第3章 分治法

第3章 分治法
内容提要
一、分治基本思想 二、二分搜索 三、归并排序 四、分治法的基本模式 五、快速排序 六、大整数的乘法 七、矩阵乘法 八、选择问题:找第k小元素
分分治割T法成(n的一) 设些计规思模想较是小=,的将相一同n个问难题以,直以接便解各决个的击大破问,题,
分而治之。
n/2
n/2
n/2
n/2
T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4
O(1)
n 1
T (n) kT (n / m) f (n) n 1
通过迭代法求得方程的解:T (n)
n logm k
logm n1
kj
f
(n / m j )
j0
注意:递归方程及其解只给出n等于m的方幂时T(n)的值,但
是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值
可以估计T(n)的增长速度。通常假定T(n)是单调上升的,从而
合并排序
一、问题 将序列A[1..n]中元素按照升序排序。
二、基本思想: 将待排序元素分成大小大致相同的2个子集合,分别对2个
子集合进行排序,最终将排好序的子集合合并成为所要求的排 好序的集合。
1.基本思想 将序列A[1……n]中元素排序 [ if 序列长度n>1 将序列A[1……mid]中元素排序; 将序列A[mid+1…..n]中元素排序 归并两个有序序列A[1……mid]和A[mid+1…..n]; ]
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
②分治法 基本思想: 首先,将原问题分解成大小基本相同的2个子问题; 然后,再分别对这2个子问题继续进行分解,直到分 解成的子问题中只有2个元素,此时可以直接求出最 大元、最小元; 最后,再进行两两合并,取2个最小元最小者,2个 最大元最大者。
寻找最大最小元素的求解过程:
8 1,8 10 8 3,8 7 8 3,8 4 8 3 3 5 6 3 2 6 6,6 6 8 2 1 3 6 1 2 1 1,2 9 4,9 13 9 4 12 14 5 11 9 4 5 3 6 2 1 9 4 5 7 4,9 16 7 5,7 15 7 1,9
T(n)= 2x *1 + 2x +2x-1… + 22 + 21
= 2x *1 +(2- 2x*2 )/(1-2) = 2x + 2x+1 - 2 =3n/2 - 2 故时间复杂度记为:O(n)
补充2: 棋盘覆盖问题 1、问题提出
3.1.2 分治算法基本步骤:
1)分解 将一个难以直接解决的大问题,分割成一些规模 较小的相同子问题,以便各个击破,分而治之。
T(n)
=
n
T(n/2)
T(n/2)
对这k个子问题分别求解。如果子问题的规模仍然不 足够小,则再划分为k个子问题,如此递归的进行下 去,直到问题规模足够小,很容易求出其解为止。
③算法描述(递归形式) int BinarySearch (int s[n], int x, int low, int high) { if (low>high) return -1; int middle=(low+high)/2; if(x==s[middle]) return middle; else if(x>s[middle]) //继续在右边查找 return BinarySearch (s, x, middle+1, high); else //继续在左边查找 return BinarySearch (s, x, low, middle-1); }
④ 算法分析
设给定的有序序列中具有n个元素。
当n=1时,查找一个元素需要常量时间,因而T(n)=O(1)。 当n>1时,T(n)= T(n/2) + O(1) = T(n/4) + 2O(1) =…… = T(n/2x) + xO(1) 分解到最后就是1个元素,则n=2x,则x=logn。
由此,T(n)=T(1)+logn=O(1)+O(logn)。
3.2 二分法(二分查找)
在算法设计中每次一个问题分解成的子问题个数一般是
固定的,每个子问题的规模也是平均分配的。当每次都
将问题分解为原问题规模的一半时,称为二分法。 二分法是分治法较常用的分解策略,数据结构课程中的 二分查找、归并排序等算法都是采用此策略实现的.
二分查找
①基本思想 如果low<high; Ⅰ、首先确定中点位置:mid=(low+high)/2; Ⅱ、然后将待检查的数据X与R[mid]比较: a、若X<R[mid],则在左边区间R[1…mid-1] 查找; b、若X>R[mid],则在右边区间R[mid+1…n] 查找; c、若X=R[mid],查找成功;
②举例 例: 查找33 08, 23, 29, 31, 37, 65, 70, 79, 80, 88,100 low=1;
在左边找 08, 23, 29, 31, 37 low=1; mid=3;
mid=(1+11)/2=6; 33<65;
high=11;
high=5 33>29 31, 37 low=4 high=5 33>31 mid=4 37
③算法描述(非递归形式) int binsearch( int a[n], int x ) //x待查数据 {int mid, low=1; int high=n; while(low<=high) {mid=(low+high)/2; if(a[mid]=x) return mid; if(a[mid]>x) high=mid-1; //继续在左边查找 else // (a[mid]<x) low=mid+1; //继续在右边查找 } return 0;//low大于high查找区间为空,查找失败 }
void max_min(int A[n], int &max,int &min) { int i; max =min = A[0]; for (i=2;i<=n; i++) { if (A[ i]<min) min = A[ i]; if (A[ i]>max) max = A[ i]; } } 时间复杂度:O(n)
分治算法基本框架:
divide-and-conquer(P) { if ( | P | <= n0) adhoc(P); //解决小规模的问题 else divide P into smaller subinstances P1,P2,...,Pk; //分解问题 for (i=1,i<=k,i++) yi=divide-and-conquer(Pi); //递归的解各子问题 return merge(y1,...,yk); //将各子问题的解合并为原问题的解 }
算法2 递归求取最大和最小元素
maxmin (int i, int j ,float &fmax, float &fmin) {int mid; float lmax, lmin, rmax, rmin; if (i=j) {fmax= a[i]; fmin=a[i];} //只有1个元素 else if (i=j-1) //只有2个元素 if(a[i]<a[j]) { fmax=a[j];fmin=a[i];} else {fmax=a[i]; fmin=a[j];} else //多于2个元素 {mid=(i+j)/2; maxmin (i,mid,lmax,lmin);//递归调用算法求最大最小 maxmin (mid+1,j,rmax,rmin);//递归调用算法求最大最小 if(lmax>rmax) fmax=lmax; else fmax=rmax; if(lmin>rmin) fmin=rmin; else fmin=lmin; }
适合用分治算法策略的问题,具有以下几个特征: 1)该问题的规模缩小到一定的程度就可以容易解决; 2)该问题可以分解为若干个规模较小的相同问题,即 该问题具有最优子结构性质; 3)该问题所分解出的各个子问题是相互独立的,即子 问题之间不包含公共的子问题。 4)利用该问题分解出子问题解可以合并为该问题解;
{ max==min=a[1]; for(i=2 i<=n i++ ) if(max < a[i]) max=a[i]; else if(min > a[i])
}
min=a[i];
分治算法设计: 问题可以简化为:在含n(n是2的幂(n>=2))个 元素的集合中寻找极大元和极小元。 用分治法(二分法)可以用较少比较次数地解决上述 问题: 1)将数据等分为两组(两组数据可能差1),目的 是分别选取其中的最大(小)值。 2)递归分解直到每组元素的个数≤2,可简单地找到最 大(小)值. 3)回溯时将分解的两组解大者取大,小者取小,合 并为当前问题的解。
分析该算法时间复杂度: 令T(n)为元素个数为n时所需比较次数(时间): 当n=2时,查找查找最大最小元只需要1次比较,T(2)=1; 时间复杂度记为O(1)。 当n>2时,T(n)=2T(n/2) + 2 T(2) =4T(n/4) + 4 T(2) + 2 T(2) =8T(n/8) + 8 + 4 + 2 =…… =2x T(n/2x) + 2x +2x-1+…+8+4+2 分解到最后只有2个元素可以求解,n/2x=2, T(n)= 2x *1 + 2x +2x-1… + 22 + 21
low=5,high=5-1 j i
在右边找 在右边找
在左边找
33<37 low=5,high=5,mid=5
跳出循环,查找失败
补充1:求最大元和最小元问题
1、问题提出
在含有n个不同元素的集合中找出最大元素和最小 元素。
2、解决问题方法
①传统方法 (逐个比较最终找到最大最小) ②分治法
①传统方法
②分治法:算法描述
void max_min( int a[ n], int i, int j, int &max, int &min) { int min1,max1,max2,min2; if(i=j) { max=min=a[ i]; } //只有1个元素 else if( j - i=1) //只有2个元素 { if(a[ i]<a[ j]) { max=a[ j]; min=a[ i]; } else { max=a[ i]; min=a[ j]; } } else //多于2个元素 {int k=(i+j)/2; //以中点k为界线分成2部分 max_min (int a, i, k, max1, min1); //在i到k部分求最大最小 max_min (int a, k+1, j, max2, min2); //在k+1到j求最大最小 if(max1<max2) max=max2; //合并取大 else max=max1; if(min1>min2) min=min2; //合并取小 else min=min1; } }
②举例 例 查找31 08, 23, 29, 31, 37, 65, 70, 79, 80, 88,100 low=1; mid=(1+11)/2=6; 31<65; high=11;