算法基本思想之减治法(一):减一法及其应用(附算法效率度量)

本文深入探讨了算法设计策略中的减治法,包括减一法及其在插入排序和深度优先搜索(DFS)与广度优先搜索(BFS)中的应用。通过递归表达式阐述了减治法的逻辑,并分析了插入排序的时间效率,指出在最坏情况下时间复杂度为O(n^2)。同时,介绍了BFS和DFS在拓扑结构中的作用,强调了它们在遍历和寻找最短路径中的重要性。
摘要由CSDN通过智能技术生成

算法设计策略

算法中的基本设计策略包括:蛮力法、分治法、减治法、变治法、时空权衡等。本专题将一一介绍这些设计策略在一些重要问题中的应用,包括排序、查找、图问题、组合问题。本文首先介绍蛮力法和减治法的应用。

蛮力法

使用蛮力法的意义在于:首先这种解法一般体现了解决问题最直接的思路,几乎对于任何问题都适用(越简单越普适);其次,在问题规模不大的时候,没有必要使用高技巧性的方法,反而耗费更多代价。并且在某些基本问题,如求数组和,求列表最大元素等,蛮力法已经是一种高效的方法。
考虑蛮力法在排序问题中的应用。一种蛮力法的方法是选择排序。每次扫描整个列表,通过逐个比较,找到最小的元素(每次更新最小的元素,最后得到的即是整个序列中的最小元素),再把每次找到的最小元素和序列中的首位元素交换(不另外放一个序列,因为原地排序节省空间)。这样,为了排出有序列,需要比较 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1)次,也就是说,其时间复杂度为 O ( n 2 ) O(n^2) O(n2)

减治法

减治法思想

减治法利用了这样一种关系:原问题的解和一个同样问题但规模较小的问题的解之间的关系。这样的表述本质上采用了递归思想,但从具体的解法层面,可以用递归求解,也可以用非递归的方法求解。本文要讲述的两种方法,一种就采用了非递归,另一种用了递归。减治法可以分为3种:

  1. 问题规模减去一个常量:规模为n的问题的解 ↔ \leftrightarrow 规模为n-1问题的解,例:插入排序、深优和广优
  2. 问题规模减去常数因子:规模为n问题的解 ↔ \leftrightarrow 规模为 n a ( a > 1 ) \frac{n}{a}(a>1) an(a>1),例:折半查找
  3. 问题规模减去可变因子:每次迭代时,规模减小的模式和其他次迭代时可以不同,例:选择问题(找顺序统计量)

本文先讨论减一技术。另几种方法在本专题后续文章中会讨论到。

算法设计中的递推类型

上面的文字表述看起来不是很清晰,特别是其没有清楚的表现出减治法和分治法的区别和联系。下面,我们用递归表达式对几种常见的、用递归表述的算法设计思路进行更清晰的表述。
减一法
由于每次的子问题就是原问题的规模减1,并且对于一个规模为n的问题的求解时间,除了包括求解规模n-1的问题,还包括对规模为n的问题化简到规模n-1问题的时间,以及对规模n-1问题扩展为规模n问题的时间,后两者的时间可以合并为一个式子,因此可以得到递归式:
T ( n ) = T ( n − 1 ) + f ( n ) T(n)=T(n-1)+f(n) T(n)=T(n1)+f(n)
减常数因子
这种情况下,每次的子问题是原问题的规模的 n b \frac{n}{b} bn,很多情况下,b为2(如折半查找,每次是和有序数组中间元素进行比较)
T ( n ) = T ( n b ) + f ( n ) T(n)=T(\frac{n}{b})+f(n) T(n)=T(bn)+f(n)

减可变因子
这种情况下,无法用递归表达式表示出来。因为每次的子问题规模取决于上一步进行的情况,而不完全取决于上一步的问题规模。如,在选择问题中,查找某个顺序统计量,对每个子问题先找中轴,再用快速排序的分区过程(两个方向相反的扫描)排出中轴两侧元素,通过此时中轴元素位置决定下一次分区的区域,亦即决定了下一个子问题的规模。

分治法
分治法的核心在于将一个问题分成若干个规模相同的子问题,每个子问题再继续分解,直到分解出可以常数时间求解的子问题,再从底向上逐层求解子问题,并对子问题解进行合并。可以看出,其与减治法最大的差别在于,每次分解出的子问题不是一个,而是多个。因此,个人理解,减治法可以看成是分治法的一种特例。分治法的递归式为:
T ( n ) = a T ( n b ) + f ( n ) T(n)=aT(\frac{n}{b})+f(n) T(n)=aT(bn)+f(n)

减一法应用之一:插入排序

算法思想

插入排序法可以类比扑克牌抓牌时候的排序过程。每新抓一张牌,会把这张牌和已有的牌比较大小,依此选择插入点。因此,每次抓牌之前,手中的牌都是一个排好序的序列。归结到算法上,是:在每次排序之前,数组A中已经有部分已经排好序的子数组B。每次要做的是取一个剩下子数组C的数,将其与B中数比较,选一个合适的位置插入。
在C对B中元素的查找并插入中,实际上有多种实现方法。假设我们要将数组从左到右排成从小到大。一种是从左到右扫描B中元素,查到B中第一个大于等于 C j C_j Cj的元素即进行插入操作。一种是从右到左扫描,查到B中第一个小于等于 C j C_j Cj的元素即进行插入。还有一种做法是折半查找。三种情况的效率上界都相同,这里只讨论从右到左扫描的查找情况。
可以发现,对这一排序方法的表述本质上基于递归思想。也就是可以基于从顶到底的递归函数调用实现算法。但对于这一问题,从底到顶的非递归方法效率会更高。

过程

可以分析这一过程的具体步骤:先在序列 A A A抽出第2个元素 a 2 a_2 a2,将其与 a 1 a_1 a1比较大小,若 a 2 < a 1 a_2<a_1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值