天津科技大学数据结构---第4章 分治法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2015-4-6
算法设计与分析--分治法
5
分治法的典型情况
原问题 的规模是n
子问题1 的规模是n/2
子问题2 的规模是n/2
子问题1的解
子问题2的解
原问题的解
2015-4-6 算法设计与分析--分治法 6
例:计算an,应用分治技术得到如下计算方法:
a
分析时 间性能
n
= n a
a 2 ´ a n
a2, …, an)划分成长度相同的两个子序列(a1, …,
a n 2 )和(a n 2
+1, …,
an),则:
2015-4-6
算法设计与分析--分治法
27
① a1, …, an的最大子段和=a1, …,an 2 的最大子段和; ② a1, …, an的最大子段和=an 2+1, …, an的最大子段和; ③ a1, …, an的最大子段和= ak ,且
j
(1≤i≤j≤n ),当序列中所有整数均为负整数时,
其最大子段和为0。例如,序列(-20, 11, -4, 13, -5,
-2)的最大子段和为:
a
k =2
4
k
= 20
2015-4-6
算法设计与分析--分治法
26
先考虑最大子段和问题的简单算法
最大子段和问题的分治策略是:
(1)划分:按照平衡子问题的原则,将序列(a1,
2015-4-6
算法设计与分析--分治法
17
一次划分示例
38 i 27
55
50 13
49
65 j 65
j
j
13 i i
27 i
55
50
38 j
49
13
2015-4-6
27
38 i j
50
j
55 j
49
65
算法设计与分析--分治法
18
算法4.5——一次划分
int Partition(int r[ ], int first, int end) { i=first; j=end; //初始化 while (i<j) { while (i<j && r[i]<= r[j]) j--; //右侧扫描 if (i<j) { r[i]←→r[j]; //将较小记录交换到前面 i++; } while (i<j && r[i]<= r[j]) i++; //左侧扫描 if (i<j) { r[j]←→r[i]; //将较大记录交换到后面 j--; } } retutn i; // i为轴值记录的最终位置 }
34
2
如果 n = 1 如果 n > 1
32
32
分解问题 31 求解每个子问题
31
3 9
31
31
3
3
9 81
3
合并子问题的解
不是所有的分治法都比简单的蛮力法更有效。
2015-4-6 算法设计与分析--分治法 7
4.1.2 数字旋转方阵
问题:输出NN(1N10)数字旋转方阵。
1 20 19 18 17 16
2015-4-6 算法设计与分析--分治法 12
二路归并排序的合并步的时间复杂性为O(n),
所以,二路归并排序算法存在如下递推式:
1 T (n) = 2T ( n 2 ) + n
n =1 n >1
可得二路归并排序的时间代价是O(nlog2n)。
二路归并排序在合并过程中需要与原始记录序列同 样数量的存储空间,因此其空间复杂性为O(n)。
j
k =i
( 3)合并:比较在划分阶段的三种情况下的最大子段和, 取三者之中的较大者为原问题的解。
2015-4-6 算法设计与分析--分治法 28
a1 … … ai … amid amid+1… aj … … an
划分 (mid = n 2)
leftsum
rightsum
递归处理 合并解 不能递归处理
2015-4-6
算法设计与分析--分治法
21
最好情况:每次划分后把待划分区间划分为长度相等的两个 子序列。 在具有n个记录的序列中,一次划分需要对整个待划分序列 扫描一遍,则所需时间为O(n)。
设T(n)是对n个记录的序列进行排序的时间,则有: T(n)=2 T(n/2)+n
=2(2T(n/4)+n/2)+n=4T(n/4)+2n =4(2T(n/8)+n/4)+2n=8T(n/8)+3n
第4章 分治法
分治法是最著名的算法设计技术。
4.1 概 述 4.2 排序问题中的分治法 4.3 组合问题中的分治法 4.4 几何问题中的分治法
2015-4-6
算法设计与分析--分治法
1
4.1 概 述
4.1.1 分治法的设计思想 4.1.2 数字旋转方阵
2015-4-6
算法设计与分析--分治法
2
4.1.1 分治法的设计思想
将一个难以直接解决的大问题,划分成一些(如k
个)规模较小的子问题,分别求解各个子问题,再合
并子问题的解得到原问题的解。 如果子问题的规模仍然不够小,可继续分解下去。
2015-4-6
算法设计与分析--分治法
3
分治法的求解过程:分-治-合
(1)划分:把规模为n的原问题划分为k个规模较 小的子问题,并尽量使这k个子问题的规模大致相同。
算法设计与分析--分治法
9
4.3.1 归并排序
二路归并排序的分治策略是: (1)划分:将待排序序列r1, r2, …, rn划分为两个 长度相等的子序列r1, …, rn/2和rn/2+1, …, rn; ( 2 )求解子问题:分别对这两个子序列进行排 序,得到两个有序子序列;
( 3 )合并:将这两个有序子序列合并成一个有 序序列。
………
=nT(1)+nlog2n=O(nlog2n) 因此,时间复杂度为O(nlog2n)。
2015-4-6 算法设计与分析--分治法 22
最坏情况:待排序记录序列正序或逆序。 此时,必须经过n-1次递归调用,而且第i趟划分需 要经过n-i次关键码的比较,因此,总的比较次数为:
n 1
1 2 (n i) = n(n 1) = O(n ) 2 i =1
2015-4-6 算法设计与分析--分治法 14
4.3.2 快速排序
快速排序的分治策略是:
(1)划分:选定一个记录作为轴值,以轴值为基准 将整个序列划分为两个子序列;
(2)求解子问题:分别对划分后的每一个子序列 递归处理; (3)合并:由于对子序列r1 … ri-1和ri+1 … rn的排序 是就地进行的,所以合并不需要执行任何操作。
k =i j
1 i n 2, n 2 + 1 j n
(2)求解子问题:对于划分阶段的情况①和②可递归求解, n 2 情况③需要分别计算 s1 = max ak (1 i , n 2)
s 2 = max
k k = n 2 +1
a (n 2 + 1 j n) ,则s1+s2为情况③的最大子段和。
(2)求解子问题:各子问题的解法与原问题的解 法通常是相同的,可以用递归的方法求解各个子问题。
(3)合并:把各个子问题的解合并起来,分治算 法的有效性很大程度上依赖于合并的实现。
2015-4-6
算法设计与分析--分治法
4
启发式规则:
1. 平衡子问题:最好使子问题的规模大
致相同。
2. 独立子问题:各子问题之间相互独立。
2015-4-6
算法设计与分析--分治法
15
[ r1 … … ri-1 ] ri [ ri+1 … … rn ]
均≤ri
轴值 均≥ri 位于最终位置
归并排序按照记录在序列中的位置对序列进行划分, 快速排序按照记录的值对序列进行划分。
2015-4-6
算法设计与分析--分治法
16
以第一个记录作为轴值,对待排序序列进行划分的过程为: (1)初始化:取第一个记录作为基准,设置两个参数i,j; (2)右侧扫描过程: (3)左侧扫描过程: (4)重复(2)(3)步,直到i与j指向同一位置,即基准记 录最终的位置。
max{leftsum, sum, rightsum} sum
a1 … … ai … amid amid+1… aj … … an
最大子段和横跨两个子序列
2015-4-6
算法设计与分析--分治法
29
算法4.7——最大子段和问题
int MaxSum(int a[ ], int left, int right) { sum=0; if (left= =right) { //如果序列长度为1,直接求解 if (a[left]>0) sum=a[left]; else sum=0; } else { center=(left+right)/2; //划分 leftsum=MaxSum(a, left, center); //对应情况①,递归求解 rightsum=MaxSum(a, center+1, right); //对应情况②,递归求解
因此,时间复杂度为O(n2)。
2015-4-6
算法设计与分析--分治法
23
平均情况:设基准记录的关键码第k小(1≤k≤n),则有:
1 n 2 n T (n) = (T (n k ) + T (k 1)) + n = T (k ) + n n k =1 n k =1
这是快速排序的平均时间性能,可以用归纳 法证明,其数量级也为O(nlog2n)。 快速排序的空间复杂性如何?
2015-4-6 算法设计与分析--分治法 19
以轴值为基准将待排序序列划分为两个子序 列后,对每一个子序列分别递归进行排序。
13 i
27 j
38
50
i
55
49
65
j 65
13
27
38
49
50
55
2015-4-6
算法设计与分析--分治法
20
算法4.6——快速排序
void QuickSort(int r[ ], int first, int end) { if (first<end) { pivot=Partition(r, first, end); //问题分解,pivot是轴值在序列中的位置 QuickSort(r, first, pivot-1); //递归地对左侧子序列进行快速排序 QuickSort(r, pivot+1, end); //递归地对右侧子序列进行快速排序 } }
2015-4-6 算法设计与分析--分治法 13
算法4.4——合并有序子序列 void Merge(int r[ ], int r1[ ], int s, int m, int t) { i=s; j=m+1; k=s; while (i<=m && j<=t) { if (r[i]<=r[j]) r1[k++]=r[i++]; //取r[i]和r[j]中较小者放入r1[k] else r1[k++]=r[j++]; } if (i<=m) while (i<=m) //若第一个子序列没处理完,则进行收尾处理 r1[k++]=r[i++]; else while (j<=t) //若第二个子序列没处理完,则进行收尾处理 r1[k++]=r[j++]; }
11
算法4.3——归并排序
void MergeSort(int r[ ], int s, int t) { int m, r1[1000]; if (s= =t) return; else { m=(s+t)/2; Mergesort(r, s, m); //归并排序前半个子序列 Mergesort(r, m+1, t); //归并排序后半个子序列 Merge(r, r1, s, m, t); //合并两个已排序的子序列 for (int i=s; i<=t; i++) //将有序序列传回数组r中 r[i]=r1[i]; } }
2 21 32 31 30 15
3 22 33 36 29 14 4 23 34 35 28 13 5 24 25 26 27 12 6 7 8 9 10 11
66的旋转方阵
2015-4-6
算法设计与分析--分治法
8
4.2 排序问题中的分治法
4.2.1 4.2.2 归并排序 快速排序
2015-4-6
2015-4-6 算法设计与分析--分治法 24
4.3 组合问题中的分治法
4.3.1 最大子段和问题 4.3.2 棋盘覆盖问题 补充: 循环赛日程安排问题
2015-4-6
算法设计与分析--分治法
25
4.3.1 最大子段和问题
给定由n个整数组成的序列(a1, a2, …, an),最大
ak 的 最 大 值 子段和问题要求该序列形如 k =i
2015-4-6 算法设计与分析--分治法 10
r1 … … rn/2
rn/2+1 ຫໍສະໝຸດ Baidu … rn
划分 递归处理
r‘1<… …<r’n/2 r’n/2+1<… …<r’n r''1<……<r''n/2<r''n/2+1 <……<r ''n
合并解
举例:8 3 2 6 7 1 5 4
2015-4-6
算法设计与分析--分治法