mirror of
https://github.com/Estom/notes.git
synced 2026-02-11 06:15:45 +08:00
递归与迭代、深搜与广搜
This commit is contained in:
21
工作日志/2021年3月16日-每日计划.md
Normal file
21
工作日志/2021年3月16日-每日计划.md
Normal file
@@ -0,0 +1,21 @@
|
||||
## 今天的计划
|
||||
* 刷完十道题
|
||||
* 开始做毕设
|
||||
|
||||
|
||||
## 今天的收获
|
||||
|
||||
* 总结了算法问题的处理步骤:问题分析、策略选择、算法设计。对问题总共分为七大类(查找线性结构、搜索分支结构、排序、字符串、排列),数据结构总共分为四大类(数组链表、堆栈队列、树、图),算法思想总共分为九大类(蛮力法、分治法、动态规划、贪心、回溯剪枝、分支限界、随机化和近似算法、递归与迭代、深搜与广搜)。明确了算法思想并不是独立的关系,而是相互重叠又相互不同的关系。
|
||||
* 明确了算法的终极目标:次序、选择、重复。使用这三个东西的组合,处理各种有趣的问题。
|
||||
* 对递归思想和迭代思想进行了彻底的理解。
|
||||
* 递推关系式。正向递推关系式和反向递推关系式。数学推导法和归纳法。递归与迭代。
|
||||
* 明确了递归的分类包括单分支递归和多分支递归。
|
||||
* 明确了递归和迭代的相同点和不同点。二者都能处理重复的问题。但是递归能够处理多分支结构。迭代需要借助特殊的数据结构才能处理多分支的数据结构。如堆栈和队列。
|
||||
* 明确了递归和迭代构件的步骤。包括向下的接口(参数),向上的接口(返回值),递归的处理(递推式),递归前和递归后。循环的递推变量(递推式),重复处理,循环的终止条件。
|
||||
* 对递归和迭代、深搜和广搜与其他部分的关系进行了处理。
|
||||
* **蛮力法**(树图特殊数据结构)与**深搜广搜**。用来遍历求值。
|
||||
* **回溯剪枝与深搜**。用来遍历求路径。
|
||||
* **分支限界与广搜**。用来遍历求路径。
|
||||
* **分治法与递归迭代**。多分支递归,单分支递归迭代都行。
|
||||
* **动态规划只能与迭代结合**。因为有很多重复的子问题,所以不能使用递归。
|
||||
* **递归和迭代用来实现深搜广搜**。
|
||||
@@ -1,5 +1,7 @@
|
||||
# 算法概述
|
||||
|
||||
> 参考文献
|
||||
> * [八种迭代思想](https://blog.csdn.net/weixin_42137700/article/details/86777003)
|
||||
## 1 基本概念
|
||||
|
||||
### 定义
|
||||
@@ -18,6 +20,11 @@
|
||||
* 算法的正确性证明方式:归纳法
|
||||
* 算法分析:正确性分析、效率分析、复杂度分析
|
||||
|
||||
### 算法的终极目标
|
||||
* **次序order**:先做什么、后做什么。前边对后边有影响。
|
||||
* **选择if-else**:要做什么、不做什么。合并相同的类别,减少分类讨论的情况。
|
||||
* **重复while-for**:一直做什么。提取相同子结构、相同子操作,进行重复利用。可以通过**递归**实现重复。
|
||||
|
||||
## 2 求解流程
|
||||
|
||||
### 求解步骤
|
||||
@@ -25,12 +32,23 @@
|
||||
|
||||

|
||||
|
||||
1. **问题分析**(确定**问题抽象**(将应用问题抽象为数学问题)、**问题分类**(搜索、排序。))
|
||||
2. **策略选择**(选择合适的**数据结构**、选择合适的**算法思想**)
|
||||
3. **算法设计**(确定**算法技术**,设计**算法流程**,数学递推关系和伪代码)
|
||||
4. **正确性证明**(查看伪代码的流程的正确性,**算法特例**)
|
||||
5. **算法分析**(分析算法**执行效率**)
|
||||
6. **程序设计**(**编程**)
|
||||
1. **问题分析**
|
||||
1. **问题抽象**将应用问题抽象为数学问题
|
||||
2. **问题分类**搜索、排序、查找
|
||||
2. **策略选择**
|
||||
1. 选择合适的**数据结构**
|
||||
2. 选择合适的**算法思想**
|
||||
3. **算法设计**
|
||||
1. 确定**算法技术**,递归技术、循环技术、位运算技术
|
||||
2. 设计**算法流程**,数学递推关系和伪代码
|
||||
4. **正确性证明**
|
||||
1. 查看伪代码的流程的正确性,手推算法过程。
|
||||
2. 验证**算法特例**
|
||||
5. **算法分析**
|
||||
1. 分析算法**执行效率**
|
||||
6. **程序设计**
|
||||
1. **编程实现**
|
||||
2. **代码调试**
|
||||
|
||||
### 更详细的说明
|
||||
|
||||
@@ -46,32 +64,40 @@
|
||||
## 3 算法分类
|
||||
|
||||
### 面向算法思想
|
||||
> 这一个主要是我们算法课程中学习到的算法。用来解决基本具体的问题。
|
||||
* 蛮力法(暴力破解、枚举、穷举)
|
||||
* 递归与分治法
|
||||
* 动态规划
|
||||
* 贪心算法
|
||||
* 回溯法
|
||||
* 分支限界法
|
||||
* 随机化算法
|
||||
> 共9中思想。任何一个问题的解决,不应该只归类于某一种算法思想。应该用到一种或几种。添加了递归和迭代作为第8种算法思想,他们主要用来处理同类型计算问题。添加了深搜和光搜作为第9中算法思想,他们主要用来处理多分支问题。
|
||||
|
||||
|
||||
> 各种算法思想之间可以交叉结合,并非完全独立的。例如在树中寻找某个节点的值,对所有节点进行遍历是蛮力思想,可以采用深搜与广搜的思想决定搜索的顺序。同时可以用递归与迭代的思想解决搜索过程。各种思想间可以相互嵌套、相互叠加,但又不完全重合,共同解决问题。
|
||||
|
||||
1. 蛮力法(穷举和遍历思想。寻找满足条件的节点值)
|
||||
2. 分治法
|
||||
3. 动态规划
|
||||
4. 贪心算法
|
||||
5. 回溯剪枝(=>深搜思想,路径作为解,而非节点值。)
|
||||
6. 分支限界(=>广搜思想,路径作为解,而非节点值。)
|
||||
7. 随机化算法和近似算法
|
||||
8. 递归与迭代
|
||||
9. 深搜与广搜(解决多分支问题的两种思想。在枚举法中用来寻找合适的节点值,搜索最优结果与路径、前置后置节点无关。在回溯剪枝和分支限界中用来寻找合适的路径,与当前的搜索路径有关)
|
||||
|
||||
### 面向数据结构
|
||||
> 在数据结构部分处理,数据结构本身就是算法的一部分,用于处理特殊数据结构的额算法。
|
||||
* 堆栈算法
|
||||
* 树算法
|
||||
* 图算法
|
||||
> 共4类结构。在数据结构部分处理,数据结构本身就是算法的一部分,用于处理特殊数据结构的算法。这里的数据结构是指,用来描述问题的数据结构是什么。比如问题描述了一张图,则应该找图相关的算法。而不是解决问题中用到的数据结构。
|
||||
|
||||
* 数组和链表结构
|
||||
* 堆栈和队列结构
|
||||
* 树结构
|
||||
* 图结构
|
||||
|
||||
### 面向问题类型
|
||||
> 这些都是常见的问题类型。
|
||||
* 搜索
|
||||
> 当前有7类问题。这些都是常见的问题类型。搜索针对多分支结构。查找针对线性数据结构。模板算法中的搜索和查找略有不同。在模板算法中,搜索的是匹配的元素的序列,查找的是单个元素。
|
||||
* 搜索问题(针对多分支结构)
|
||||
* 广度优先搜索
|
||||
* 深度优先搜索
|
||||
* 排序
|
||||
* 排序问题
|
||||
* 选择排序
|
||||
* 冒泡排序
|
||||
* 快速排序
|
||||
* 桶排序
|
||||
* 查找(匹配)
|
||||
* 查找问题(匹配,针对线性结构)
|
||||
* 顺序查找
|
||||
* 二分查找
|
||||
* 插值查找
|
||||
@@ -79,7 +105,7 @@
|
||||
* 树表查找
|
||||
* 分块查找
|
||||
* 哈希查找
|
||||
* 字符串处理
|
||||
* 字符串问题
|
||||
* 排列组合
|
||||
* 任务分配
|
||||
* 背包问题
|
||||
|
||||
184
算法/A类:基本算法/11 递归与迭代.md
Normal file
184
算法/A类:基本算法/11 递归与迭代.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# 递归与迭代。
|
||||
|
||||
> 参考文献
|
||||
> * [递归详解](https://www.cnblogs.com/ncby/p/10551176.html)
|
||||
> * [递归算法讲解](https://blog.csdn.net/weixin_43025071/article/details/89149695)
|
||||
> * [递归算法的理解](https://blog.csdn.net/allenchenhh133/article/details/80291252)
|
||||
> * [递归的本质](https://blog.csdn.net/xiongping_/article/details/43601165)
|
||||
|
||||
|
||||
> 由于递归与迭代的特殊性。在这里单独列出一种思想。递归与迭代思想,用来处理所有的重复的操作。如分治法的相同子操作、动态规划的相同子操作、深度优先搜索、广度优先搜索的相同子操作。
|
||||
## 1 递归法概述
|
||||
|
||||
### 基本思想
|
||||
* 直接或间接的调用自身的算法称为递归算法。用函数自身给出定义的函数称为递归函数。
|
||||
* 递归的基本思想就是把规模大的问题转化为规模小的相似的子问题来解决。
|
||||
* 递归的数学模型其实就是**数学归纳法**。可以用**反向递推式**表示递归的过程。(使用正向递推式表示循环的过程)
|
||||
|
||||
### 线性收缩递归算法
|
||||
* 递推关系式
|
||||
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
o(1) & n=1 \\
|
||||
\sum_{i=1}^k a_iT(n-i)+f(n) & n>1
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
* 求解递推关系式
|
||||
$$
|
||||
T(n)=a^{n-1}T(1)+\sum_{i=2}^na^{n-i}f(i)
|
||||
$$
|
||||
* 关系式说明
|
||||
|
||||

|
||||
### 等比收缩递归算法
|
||||
|
||||
* 递推关系式
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(1)&n=1 \\
|
||||
aT(\frac{n}{b})+f(n) & n>1
|
||||
\end{cases}
|
||||
$$
|
||||
* 求解递推关系式
|
||||
$$
|
||||
T(n)=n^{\log_ba} +\sum_{i=2}^{\log_bn-1}a^jf(n/b^j)
|
||||
$$
|
||||
* 关系式说明
|
||||
|
||||
$$
|
||||
T(n)=O(n^{\log_ba})+O(f(n))\log_bn
|
||||
$$
|
||||
* 其真正的时间复杂度,由前后两部分决定。可以通过计算,得到较大部分的时间复杂度,为整体的时间复杂度。
|
||||
|
||||
* 当f(n)为常数时
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(n^{\log_ba}) & a\not = 1\\
|
||||
O(\log n) & a=1
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
* 当f(n)=cn时
|
||||
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(n)&a<b\\
|
||||
O(n\log n)& a=b\\
|
||||
O(n^{log_b^a})&a>b
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
## 2 递归的分类
|
||||
### 直接递归和间接递归
|
||||
* 直接递归,是指函数自己调用自己的情况。
|
||||
* 间接递归,是指调用其他函数时,在其他函数中又调用了自己的情况。
|
||||
### 头递归和尾递归
|
||||
|
||||
* 头递归:递归发生在函数的其他处理代码之前(或理解为,递归发生在函数的头部或顶部)。**需要先解决后续问题,上层依赖下层,最顶层得到结果,直接返回**。
|
||||
* 需要使用后续递归后的结果,参与本层的计算,然后返回给上一层。这时,需要在下层的递归完成后,才能计算。如归并计算,需要下一层拍好顺序,这一次才会执行归并操作。
|
||||
* 尾递归:递归发生在函数其他处理代码的后面(或理解为,递归发生在函数的尾部)。**需要先解决当前问题,下层依赖上层,最底层得到结果,返回顶层**。
|
||||
* 本层内的计算是为了确定递归过程中的条件。且下一层返回的结果,能够作为本层的结果返回。本层不知道改成的结果,结果取决于最底层。如搜索树的最大深度,只有递归到叶节点才知道最大深度是多少。
|
||||
* 中间部分递归:递归发生在函数体的中间部分。
|
||||
* 头递归和尾递归只是描述递归发生的相对顺序。实际上在递归过程中,递归可以发生在任何位置。递归前的代码负责处理本层的与下一层无关的内容。递归后的代码负责利用下一层的返回值或其他变量处理内容。
|
||||
|
||||
### 单分支递归和多分支递归
|
||||
* 单分支递归:每一层只是常数级别缩小问题的规模。进行一次递归处理下一个问题。每一层只**调用一次递归函数**。如阶乘问题青蛙跳问题等。
|
||||
* 多分支递归:当一个问题可以分为多个相同的子问题的时候。在同一层进行多分支递归。每一层**多次调用递归函数**。如树和图的遍历问题,有多个下层子节点。
|
||||
## 3 递归的实现
|
||||
|
||||
### 递归前的预处理
|
||||
1. 提取重复的逻辑,缩小问题规模。
|
||||
2. 只有写出**反向递推关系式**,才知道递归的参数、递归的返回值和递归的执行关系。
|
||||
|
||||
|
||||
### 递归的实现步骤
|
||||
|
||||
1. 设计**递归的参数**。首先确定每一次递归,上一层需要提供给下一层的内容。相当于上层---->下层的接口。
|
||||
2. 设计**递归的返回值**。设计递归需要返回的内容,即提供给上一层的内容。相当于下层---->上层的接口。
|
||||
3. 设计**递归的执行**。找出函数的等价关系式。设计如何开始递归。怎样调用递归。有了上一层的参数和返回值的需求,相当于提供了一个函数的接口。那么就可以调用递归函数,开始递归了。
|
||||
4. 设计**递归的终止条件**。一旦开始递归,就要设计递归的终止条件。
|
||||
5. **递归前的数据处理**。在递归前需要处理的数据,提供给递归函数。
|
||||
6. **递归后的数据处理**。在递归后需要处理的数据。提供给上层函数和最终结果。
|
||||
|
||||
### 递归的终止条件
|
||||
* 终止递归:终止递归有两种思路。
|
||||
1. 本层不满足条件。终止递归。当进入本层后,首先判断递归是否终止。
|
||||
2. 下一层不满足条件。终止递归。当要进行递归前,判断是否还需要进行递归。前提是直到下一层是否满足条件的计算。
|
||||
* 本层判断更符合递归的思想,且在实现过程中,也相对简单。
|
||||
|
||||
### 递归算法理解
|
||||
|
||||
* 递归算法本质上是一种自顶向下的思考模式。即数学上所说的归纳法。有结果一步一步归纳,得到验证其条件的正确性。问题规模逐渐变小。
|
||||
* 非递归算法的本质是一种自底向上的思考模式。即数学上所说的推导法。将一些零碎的部分逐渐求解,渐渐得到最终的结果。问题逐渐组装成目标问题。
|
||||
|
||||
* 在使用递归的时候,应该从顶层考虑怎么分割。在使用非递归算法的时候,应该考虑怎样从顶层进行组合。
|
||||
|
||||
|
||||
## 4 迭代法概述
|
||||
|
||||
### 概念
|
||||
* 迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,在解决问题时总是重复利用一种方法。与迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近似迭代。
|
||||
* 循环其实和递归具有相同的特性,即做重复任务。
|
||||
|
||||
|
||||
## 5 迭代法的时间复杂度
|
||||
* 取决于迭代嵌套的数量。每一层迭代为常数级别则:
|
||||
|
||||
$$
|
||||
O(m*n*...*k)(m,n,k表示嵌套迭代的复杂度)\\
|
||||
O(m+n+...+k)(m,n,k表示并列迭代的复杂度)
|
||||
$$
|
||||
|
||||
## 6 迭代法实现
|
||||
|
||||
* 迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。在使用迭代算法解决问题时,需要做好如下3个方面的工作。
|
||||
1. 确定迭代变量
|
||||
2. 建立迭代关系
|
||||
3. 控制迭代过程
|
||||
|
||||
### 6.1 确定迭代变量
|
||||
|
||||
* 在可以使用迭代算法解决的问题中,至少存在一个迭代变量,即直接或间接地不断由旧值递推出新值的变量。
|
||||
|
||||
### 6.2 建立迭代关系式
|
||||
|
||||
* 迭代关系式是指如何从变量的前一个值推出其下一个值的公式或关系。通常可以使用递推或倒推的方法来建立迭代关系式,迭代关系式的建立是解决迭代问题的关键。
|
||||
|
||||
### 6.3 控制迭代过程
|
||||
|
||||
* 在编写迭代程序时,必须确定在什么时候结束迭代过程,不能让迭代过程无休止地重复执行下去。通常可分为如下两种情况来控制迭代过程:
|
||||
* 所需的迭代次数是个确定的值,可以计算出来,可以构建一个固定次数的循环来实现对迭代过程的控制;
|
||||
* 所需的迭代次数无法确定,需要进一步分析出用来结束迭代过程的条件。
|
||||
|
||||
## 7 递归与迭代的区别与联系
|
||||
|
||||
* 二者都能处理重复的逻辑。降低算法的复杂度。
|
||||
* 二者都能够使用递推关系式表示。**迭代**使用**正向递推关系式**,在数学上称为**推导法**,从最初的已知条件逐渐推导出自己想要的结果。**递归**使用**反向递推关系式**,在数学上称为**归纳法**,从结果触发,逐渐寻找满足计算的初始条件。
|
||||
* 递归能够直接处理多个分支的问题(多分支递归)。循环需要借助特殊的数据结构保存另一个分支的状态,解决多分支问题。如堆栈和队列可以用来实现深搜广搜过程中保存其他分支。
|
||||
|
||||
## 8 递归与迭代思想与其他思想的结合
|
||||
|
||||
|
||||
### 与分治法
|
||||
|
||||
* 分治法具有**最优子结构性质**。但是分治法一半是多分支结构,在分解过程中**递归**算法解决问题。
|
||||
* 减治法也具有**最优子结构性质**。但是减治法是是单分支结构,可以使用**递归**算法解决问题,也可以使用**迭代**算法解决问题。
|
||||
|
||||
### 动态规划
|
||||
|
||||
* 动态规划具有**最优子结构性质**。但是子问题之间一半相互依赖,并且上层问题**有重叠子问题**,如果使用递归的话,需要多次调用相同的子问题的解。
|
||||
* 所以动态规划一般使用**迭代**解决。使用公共变量记住重叠子问题的解,避免重复计算。!!!!
|
||||
|
||||
### 与深度优先搜索
|
||||
|
||||
* 可以使用**递归**。进行前序、中序、后序的深度搜索。
|
||||
* 可以使用**迭代+栈**的方式,保存多分支结构的其他分支的状态,实现深度优先搜索。
|
||||
|
||||
|
||||
### 与广度优先搜索
|
||||
|
||||
* 一般使用**循环+队列**的方式,实现同一层次的节点的处理。使用队列保存同一层的其他节点的状态。
|
||||
|
||||
|
||||
33
算法/A类:基本算法/12 深搜与光搜.md
Normal file
33
算法/A类:基本算法/12 深搜与光搜.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 深度优先搜索与广度优先搜索
|
||||
|
||||
* 用来处理**多分支结构**
|
||||
* 对于现行问题或单分支结构的问题。不适用深度搜索和广度搜索
|
||||
|
||||
|
||||
## 1 深度搜索
|
||||
|
||||
* 深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
|
||||
|
||||
## 2 广度搜索
|
||||
|
||||
* 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。
|
||||
|
||||
|
||||
## 3 深搜广搜与其他算法思想
|
||||
|
||||
### 与蛮力法
|
||||
|
||||
* **蛮力法的深搜和广搜**。用来搜索树和图中满足条件的节点值。与前置节点或者后置节点没有必然的关系。即一般**无后效性**,前直接点不会影响后置节点的解。
|
||||
|
||||
### 与回溯剪枝的结合
|
||||
|
||||
* **回溯剪枝与深搜结合**。一般用来搜索满足条件的路径。与前置节点和后置节点有必然联系。一般具有**多米诺性质**,叶子节点的解一定满足其父节点。叶子结点为真则父节点一定为真。同理父节点为假则叶子结点一定为假(逆否命题)。用父节点为假的情况进行剪枝操作。
|
||||
|
||||
### 与分治限界的结合
|
||||
|
||||
* **分支限界与广搜结合**。一般用来搜索满足条件的路径。与前置节点和后置节点有必然联系。一般具有多米诺性质。
|
||||
|
||||
|
||||
### 与递归和迭代思想的结合
|
||||
|
||||
> 参考递归和迭代的章节。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 分治法
|
||||
|
||||
## 0 分治法概述
|
||||
## 1 分治法概述
|
||||
### 基本思想
|
||||
|
||||
* 求解问题算法的复杂性一般都与问题规模相关,问题规模越小越容易处理。
|
||||
@@ -40,106 +40,7 @@ divide-and-conquer(P){
|
||||
|
||||
可以通过过计算递归法的时间复杂度,计算分治法的时间复杂度。
|
||||
|
||||
|
||||
## 0 递归法概述
|
||||
|
||||
### 基本思想
|
||||
* 直接或间接的调用自身的算法称为递归算法。用函数自身给出定义的函数称为递归函数。
|
||||
|
||||
### 线性收缩递归算法
|
||||
* 递推关系式
|
||||
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
o(1) & n=1 \\
|
||||
\sum_{i=1}^k a_iT(n-i)+f(n) & n>1
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
* 求解递推关系式
|
||||
$$
|
||||
T(n)=a^{n-1}T(1)+\sum_{i=2}^na^{n-i}f(i)
|
||||
$$
|
||||
* 关系式说明
|
||||
|
||||

|
||||
### 等比收缩递归算法
|
||||
|
||||
* 递推关系式
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(1)&n=1 \\
|
||||
aT(\frac{n}{b})+f(n) & n>1
|
||||
\end{cases}
|
||||
$$
|
||||
* 求解递推关系式
|
||||
$$
|
||||
T(n)=n^{\log_ba} +\sum_{i=2}^{\log_bn-1}a^jf(n/b^j)
|
||||
$$
|
||||
* 关系式说明
|
||||
|
||||
$$
|
||||
T(n)=O(n^{\log_ba})+O(f(n))\log_bn
|
||||
$$
|
||||
* 其真正的时间复杂度,由前后两部分决定。可以通过计算,得到较大部分的时间复杂度,为整体的时间复杂度。
|
||||
|
||||
* 当f(n)为常数时
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(n^{\log_ba}) & a\not = 1\\
|
||||
O(\log n) & a=1
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
* 当f(n)=cn时
|
||||
|
||||
$$
|
||||
T(n)=\begin{cases}
|
||||
O(n)&a<b\\
|
||||
O(n\log n)& a=b\\
|
||||
O(n^{log_b^a})&a>b
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
### 直接递归和简介递归
|
||||
* 直接递归,是指函数自己调用自己的情况。
|
||||
* 间接递归,是指调用其他函数时,在其他函数中又调用了自己的情况。
|
||||
### 头递归和尾递归
|
||||
|
||||
* 头递归:递归发生在函数的其他处理代码之前(或理解为,递归发生在函数的头部或顶部)
|
||||
* 需要使用后续递归后的记过,参与本层的计算,然后返回给上一层。这时,需要在下层的递归完成后,才能计算。如归并计算,需要下一层拍好顺序,这一次才会执行归并操作。
|
||||
* 尾递归:递归发生在函数其他处理代码的后面(或理解为,递归发生在函数的尾部)
|
||||
* 本层内的计算是为了确定递归过程中的条件。且下一层返回的结果,能够作为本层的结果返回。本层不知道改成的结果,结果取决于最底层。如搜索树的最大深度,只有递归到叶节点才知道最大深度是多少。
|
||||
* 中间部分递归:递归发生在函数体的中间部分。
|
||||
* 头递归和尾递归只是描述递归发生的相对顺序。实际上在递归过程中,递归可以发生在任何位置。递归前的代码负责处理本层的与下一层无关的内容。递归后的代码负责利用下一层的返回值或其他变量处理内容。
|
||||
|
||||
### 递归的终止条件
|
||||
* 终止递归:终止递归有两种思路。
|
||||
1. 本层不满足条件。终止递归。当进入本层后,首先判断递归是否终止。
|
||||
2. 下一层不满足条件。终止递归。当要进行递归前,判断是否还需要进行递归。前提是直到下一层是否满足条件的计算。
|
||||
* 本层判断更符合递归的思想,且在实现过程中,一般也相对简单。
|
||||
|
||||
### 递归的实现
|
||||
|
||||
1. 设计递归的参数。首先确定每一次递归,上一层需要提供给下一层的内容。
|
||||
2. 设计递归的返回值。设计递归需要返回的内容,即提供给上一层的内容。
|
||||
3. 设计递归的开始。设计如何开始递归。怎样调用递归。有了上一层的参数和返回值的需求,相当于提供了一个函数的接口。那么就可以调用递归函数,开始递归了。
|
||||
4. 设计递归的终止条件。一旦开始递归,就要设计递归的终止条件。
|
||||
5. 递归前的数据处理。在递归前需要处理的数据,提供给递归函数。
|
||||
6. 递归后的数据处理。在递归后需要处理的数据。提供给上层函数和最终结果。
|
||||
|
||||
|
||||
|
||||
### 递归算法理解
|
||||
|
||||
* 递归算法本质上是一种自顶向下的思考模式。即数学上所说的归纳法。有结果一步一步归纳,得到验证其条件的正确性。问题规模逐渐变小。
|
||||
* 非递归算法的本质是一种自底向上的思考模式。即数学上所说的推导法。将一些零碎的部分逐渐求解,渐渐得到最终的结果。问题逐渐组装成目标问题。
|
||||
|
||||
* 在使用递归的时候,应该从顶层考虑怎么分割。在使用非递归算法的时候,应该考虑怎样从顶层进行组合。
|
||||
|
||||
###
|
||||
|
||||
## 0 减治法概述
|
||||
## 2 减治法概述
|
||||
|
||||
### 基本思想
|
||||
|
||||
@@ -175,7 +76,7 @@ f(n) = f (n-1) *a 如果n > 1
|
||||
* 减治法直接通过运算将问题的规模减小。问题数量没有增加。
|
||||
|
||||
|
||||
## 0 变治法概述
|
||||
## 3 变治法概述
|
||||
|
||||
### 基本思想
|
||||
|
||||
@@ -185,7 +86,7 @@ f(n) = f (n-1) *a 如果n > 1
|
||||
|
||||
> 根本上是转换问题的思路。
|
||||
|
||||
## 1 分治法应用
|
||||
## 4 分治法应用
|
||||
|
||||
### 排列问题
|
||||
|
||||
@@ -214,7 +115,7 @@ O(n)
|
||||
|
||||
### 棋盘覆盖问题
|
||||
|
||||
## 2 减治法应用
|
||||
## 5 减治法应用
|
||||
|
||||
### 拓扑排序
|
||||
|
||||
@@ -233,7 +134,7 @@ O(n)
|
||||
### 二叉树查找
|
||||
|
||||
|
||||
## 3 变治法应用
|
||||
## 6 变治法应用
|
||||
### 元素唯一性-预排序算法
|
||||
|
||||
### 模式计算-预排序算法
|
||||
Reference in New Issue
Block a user