在第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_MAXsum = 0for i =mid downto low:sum = sum + A[i]if sum > left-sum:left-sum = summax-left = iright-sum = -INT_MAXsum = 0max-right = 0for j = mid + 1 to highsum = sum + A[j]if sum > right-sum:right-sum = summax-right = jreturn (max-left, max-right, left-sum + right-sum)

(由于伪代码中返回值时有多个参数,突然不知道用c/c++语言怎么实现,故采用python语言实现。欢迎各位高手用c/c++语言实现该算法)采用python代码实现的完整程序为:

def findMaxCrossingSubArray(A, low, mid, high):leftSum = -65536sum2 = 0maxLeft = 0for i in range(mid, low, -1):sum2 = sum2 + A[i]if sum2 > leftSum:leftSum = sum2maxLeft = irightSum = -65536sum2 = 0maxRight = 0for j in range(mid+1, high):sum2 = sum2 + A[j]if sum2 > rightSum:rightSum = sum2maxRight = jreturn maxLeft, maxRight, leftSum + rightSum

FIND-MAX-CROSSING-SUBARRAY的运行时间为线性时间,则最大子数组问题的分治法算法的伪代码如下:

FIND-MAXIMUM-SUBARRAY(A, low, high)
1     if high == low
2         return(low, high, A[low])
3     else mid = (low + high) / 2
4         (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-num
8                    return (left-low, left-high, left-sum)
9        elseif right-sum >= left-sum and rigth-sum >=cross-sum
10                  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) / 2leftLow, 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, leftSumelif rightSum>=leftSum and rightSum>=crossSum:return rightLow, rightHigh, rightSumelse:return crossLow, crossHigh, crossSum

寻找最大子数组的递归式与归并排序的递归式是相同的,故算法时间复杂度为O(nlgn)。

算法导论读书笔记 第4章 分治策略相关推荐

  1. 算法导论 第一部分 第四章-分治策略

    算法导论 第一部分 第四章-分治策略 我们知道分治策略,就是3个步骤,分解.解决.合并. 子问题足够大,需要递归解决,叫做递归情况. 子问题足够小,就进入了基本情况. 递归式 递归式可以很方便的表示算 ...

  2. 算法导论读书笔记(7)

    算法导论读书笔记(7) 目录 快速排序 快速排序的简单Java实现 快速排序的性能 最坏情况划分 最佳情况划分 快速排序的随机化版本 比较排序 快速排序 快速排序是一种原地排序算法,对包含 n 个数的 ...

  3. 算法导论读书笔记(8)

    算法导论读书笔记(8) 目录 计数排序 计数排序的简单Java实现 基数排序 基数排序的简单Java实现 桶排序 计数排序 计数排序 假设 n 个输入元素中的每一个都是介于0到 k 之间的整数,此处 ...

  4. 计算机系统导论第九章,计算机系统导论 -- 读书笔记 -- 第三章 程序的机器级表示 (持续更新)...

    计算机系统导论 -- 读书笔记 -- 第三章 程序的机器级表示 (持续更新) 第三章 程序的机器级表示 3.1 历史观点 3.2 程序编码 1. 命令行 (1)编译 Linux> gcc -Og ...

  5. 算法导论读书笔记(19)

    http://www.cnblogs.com/sungoshawk/p/3802553.html 算法导论读书笔记(19) 目录 最优二叉搜索树 步骤1:一棵最优二叉查找树的结构 步骤2:一个递归解 ...

  6. 算法导论读书笔记-第十九章-斐波那契堆

    算法导论第19章--斐波那契堆 可合并(最小)堆(mergeable min-heap) : 支持以下5种操作的一种数据结构, 其中每一个元素都有一个关键字: MAKE-HEAP(): 创建和返回一个 ...

  7. 算法导论学习笔记 第2章 算法基础

    本章介绍了一个贯穿本书的框架,后续的算法设计都是在这个框架中进行的. 本章通过插入排序和归并排序两种常见的算法来说明算法的过程及算法分析,在分析插入排序算法时,书中是用了循环不变式证明了算法的正确性, ...

  8. 算法导论学习笔记 第7章 快速排序

    对于包含n个数的输入数组来说,快速排序是一种时间复杂度为O(n^2)的排序算法.虽然最环情况的复杂度高,但是快速排序通常是实际应用排序中最好的选择,因为快排的平均性能非常好:它的期望复杂度是O(nlg ...

  9. 算法导论学习笔记 第6章 堆排序

    在本章中介绍了另一种排序算法:堆排序(heapsort).与归排序一样,但不同于插入排序的是,堆排序的时间复杂度式(Onlgn).而与插入排序相同,但不同于归并排序的是,堆排序同样具有空间原址性(我理 ...

最新文章

  1. jQuery中hover与mouseover和mouseout的区别分析
  2. vue笔记(二)Vue-class与style、事件、计算属性、数据监听、指令+自定义指令、过滤器
  3. 【Ubuntu14】Nginx+PHP5+Mysql记录
  4. React Portals与Error Boundaries
  5. mysql配置环境变量,进阶加薪全靠它!
  6. CCF NOI1000 加密算法
  7. php中的each()用法和list()用法
  8. centos7阿里yum源报问题
  9. 01-AHP层次分析法
  10. 指数分布的极大似然估计
  11. tornado程序中出现ValueError: invalid literal for int() with base 16: ‘
  12. LA 5846 霓虹灯广告牌(单色三角形问题)
  13. JS修改链接地址实现页面动态跳转的方法
  14. php扩展-ioncube组件的安装方法_如何安装ioncube扩展
  15. 通信设计院,到底是干啥的?
  16. 微信公众号开发笔记(八)发送图片消息
  17. Titan图形数据库的应用实例讲解
  18. html增加语音朗读功能,给wordpress主题添加上语音播放文章内容文本朗读功能
  19. Python 列表元组拆分为多个列表
  20. 视觉SLAM笔记(33) 对极约束求解相机运动

热门文章

  1. C# 如何生成一个时间戳
  2. java+jtextfield+取值_[求助]JTextfield 取值问题!
  3. java发送http请求的四种方式
  4. 【IDEA】2020 断点(BreakPoints)调试(亲测)
  5. 进程、线程和协程的理解
  6. docker部署django项目、mysql主从搭建、django实现读写分离
  7. HTTP解决设置返回header的code码为400仍然是200的问题
  8. Yii的查询后缀限定
  9. 脉冲宽度调制pdm_0-500V可调0-30A高频脉冲电源广元厂家
  10. 日期时间选择器-jeDate日期控件