算法导论读书笔记 第4章 分治策略
来源:互联网 发布:linux控制台中文乱码 编辑:程序博客网 时间:2024/05/22 14:45
在第2章中,归并排序算法使用了分治策略。即在分治策略中,递归地求解一个问题,在每层递归中应包含三个步骤:
分解(Divide)步骤将问题画分为一些子问题,子问题的形式与原问题一样,只是规模更小。
解决(Conquer)步骤递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。
合并(Combine)步骤将子问题的解组合成原问题的解。
当子问题足够大时,需要递归求解时,我们称之为递归情况(recursive case)。当子问题变得足够小,不需要在递归时,此时已进入基本情况(base case)。有时,除了与原问题形式完全一样的规模更小的子问题外,还需求解与原问题不完全一样的子问题,但这种情况可以看做是合并步骤的一部分。本章中会看到两个基于分治策略的算法。其中一个是求解最大子数组问题,其输入是一个数值数组,算法需要确定有最大和的连续子数组。
递归式
递归式是与分治法紧密相关的,因为递归式子可以很自然地刻画分治算法的运行时间。一个递归时就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数。用递归式描述MERGE-SORT过程的最坏运行时间为T(n):
求解可得T(n) = O(nlgn)。
4.1 最大子数组问题
最大子数组问是指需找数组中和最大的非空连续子数组,称这样的子数组为最大子数组(maximum subarray)。如下图数组A中,A[1.. 16]的最大子数组为A[8.. 11],其和为43。
最大子数组中只有包含负数时才有意义,如果所有数组元素都是非负的,最大子数组问题没有任何难度,以为整个数组的和可定是最大的。
使用分治策略求解最大子数组问题
假定要寻找子数组A[low.. high]的最大子数组。使用分治策略意味着要将数组划分为两个规模尽量相等的子数组。即找到子数组的中央位置,比如mid,然后考虑求解两个子数组A[low.. mid]和A[mid + 1.. high]。如下图所示,A[low.. high]的任意连续子数组A[i.. j]所处的位置必然是如下三种情况之一:
1 完全位于子数组A[low.. mid]中, 因此 low <= i <= j <= mid
2 完全位于子数组A[mid + 1, high]中, 因此 mid < i <= j <= high
3 跨越了中点, 因此low <= i <= mid < j <=high
因此,A[low.. high]的最大子数组所处的位置必然是这三种情况之一。通过调用FIND-MAX-CROSSING-SUBARRAY接受数组A和下标low,mid和high为输入,返回一个下标元组划定跨越中点的最大子数组的边界,并返回最大子数组中的和。为代码如下:(-INT_MAX表示负的无穷大)
Find-Max-Crossing-SUBARRAY(A, low, mid, high): left-sum = -INT_MAX sum = 0 for i =mid downto low: sum = sum + A[i] if sum > left-sum: left-sum = sum max-left = i right-sum = -INT_MAX sum = 0 max-right = 0 for j = mid + 1 to high sum = sum + A[j] if sum > right-sum: right-sum = sum max-right = j return (max-left, max-right, left-sum + right-sum)
(由于伪代码中返回值时有多个参数,突然不知道用c/c++语言怎么实现,故采用python语言实现。欢迎各位高手用c/c++语言实现该算法)采用python代码实现的完整程序为:
def findMaxCrossingSubArray(A, low, mid, high): leftSum = -65536 sum2 = 0 maxLeft = 0 for i in range(mid, low, -1): sum2 = sum2 + A[i] if sum2 > leftSum: leftSum = sum2 maxLeft = i rightSum = -65536 sum2 = 0 maxRight = 0 for j in range(mid+1, high): sum2 = sum2 + A[j] if sum2 > rightSum: rightSum = sum2 maxRight = j return maxLeft, maxRight, leftSum + rightSumFIND-MAX-CROSSING-SUBARRAY的运行时间为线性时间,则最大子数组问题的分治法算法的伪代码如下:
FIND-MAXIMUM-SUBARRAY(A, low, high)1 if high == low2 return(low, high, A[low])3 else mid = (low + high) / 24 (left-low, left-high, left-sum) = FIND-MAXIMUM-SUBARRAY(A, low, mid)5 (right-low, right-high, right-sum) = FIIND-MAXIMUM-SUBARRAY(A, mid+1, high)6 (cross-low, cross-high, cross-sum) = FIND-MAXMUM-SUBARRAY(A, low, mid, higt)7 if left-sum>=right-sum and left-sum >= cross-num8 return (left-low, left-high, left-sum)9 elseif right-sum >= left-sum and rigth-sum >=cross-sum10 return(right-low, right-high, right-sum)11 else return (cross-low, cross-high, cross-sum)初始调用FIND-MAXIMUM-SUBARRAY(A, 1, A.Length)会求出A[1.. n]的最大子数组。
pyhton语言实现的完整程序为:
def findMaximumSubArrary(A, low, high): if high == low: return low, high, A[low] else: mid = (low + high) / 2 leftLow, leftHigh, leftSum = findMaximumSubArrary(A, low, mid) rightLow, rightHigh, rightSum = findMaximumSubArrary(A, mid + 1, high) crossLow, crossHigh, crossSum = findMaxCrossingSubArray(A, low, mid, high) if leftSum>=rightSum and leftSum>=crossSum: return leftLow, leftHigh, leftSum elif rightSum>=leftSum and rightSum>=crossSum: return rightLow, rightHigh, rightSum else: return crossLow, crossHigh, crossSum寻找最大子数组的递归式与归并排序的递归式是相同的,故算法时间复杂度为O(nlgn)。
- 算法导论读书笔记 第4章 分治策略
- 《算法导论》第4章 分治策略 个人笔记
- 算法导论 第4章 源程序 分治策略 最大子数组 Strassen算法
- 算法导论第4章 分治
- 【算法导论】分治策略
- 《算法导论》读书笔记(2)复杂度、分治策略 部分习题
- 【技术文档】《算法设计与分析导论》R.C.T.Lee等·第4章 分治策略
- 第 4 章 分治策略
- 第4章 分治策略——strassen算法
- 算法导论第四章-分治策略-Cpp代码实现
- 算法导论_第四章_分治策略
- 《算法导论》读书笔记(三)——分治策略之和最大连续子序列
- 算法导论,分治策略,最大子数组
- 算法导论——分治策略
- 读书笔记:算法导论第1章
- 算法导论第2章(4) 分治法的应用 找逆序对 (习题2-4)
- 读书笔记:《算法导论》,第2章:算法基础
- 算法导论-第4章
- VMware中Bridged,NAT,Host-Only三种工作模式介绍
- hello linux
- 十个最值得阅读学习的C开源项目代码
- GridLayout使用实例2
- CocoaPods安装和使用教程
- 算法导论读书笔记 第4章 分治策略
- linux内核之kfifo队列
- 怎么使用spinOnce以一定频率发布消息
- 物联12:rfid低频和高频天线技术
- JConsole观察分析Java程序的运行
- 孪生素数问题
- WM_MOUSELEAVE和WM_MOUSEHOVER消息
- 如何在数据库应用中发挥SSD的优势
- Unique Paths