算法初步

This commit is contained in:
estomm
2020-01-02 22:19:36 +08:00
parent 2a03155c38
commit f005fca50e
20 changed files with 396 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
# 算法概述
## 1 基本概念
### 定义
算法是一系列解决问题的清晰指令,对于符合一定规范的输入,算法能够在有限时间内获得所要求的输出。算法是解决问题的一种方法或过程,它是由若干条指令组成的有穷序列。
### 特征
输入:有零或多个外部量作为算法的输入。
输出:算法产生至少一个量作为输出。
确定性:组成算法的每条指令清晰、无歧义。
有效性:算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步。
有限性:算法中每条指令的执行次数有限,执行每条指令的时间也有限。
### 算法的描述
* 算法的描述方式:自然语言、流程图、伪代码
* 算法的正确性证明方式:归纳法
* 算法分析:正确性分析、效率分析、复杂度分析
## 2 求解流程
### 求解步骤
![](image/算法流程.png)
## 3 算法分类
### 面向算法范式
> 这一个主要是我们算法课程中学习到的算法。用来解决基本具体的问题。
* 蛮力法(暴力破解、枚举、穷举)
* 递归与分治法
* 动态规划
* 贪心算法
* 回溯法
* 分支限界法
* 随机化算法
### 面向数据结构
> 在数据结构部分处理,数据结构本身就是算法的一部分,用于处理特殊数据结构的额算法。
* 堆栈算法
* 树算法
* 图算法
### 面向问题类型
> 这些都是常见的问题类型。
* 搜索
* 广度优先搜索
* 深度优先搜索
* 排序
* 选择排序
* 冒泡排序
* 快速排序
* 桶排序
* 查找
* 顺序查找
* 二分查找
* 插值查找
* 菲波那切查找
* 树表查找
* 分块查找
* 哈希查找
* 字符串处理
* 排列组合
* 任务分配
* 背包问题
* 集合问题
* 数值问题
### 智能算法
> 更高级的算法。
* 蚁群算法
* 模拟退火算法
* 遗传算法

View File

@@ -0,0 +1,136 @@
# 算法效率
> 目录
1. 算法效率的度量
2. 函数的渐进的界
3. 算法的基本复杂性类型
4. 算法复杂性分析的基本方法
5. 非递归算法的复杂性分析
6. 递归算法的复杂性分析
7. 递归算法与非递归算法比较
8. 经验分析方法
9. 算法可视化
## 1 算法效率的度量
### 分类
* 时间效率
* 空间效率
### 算法效率的表示
N-要解决问题的规模
I-算法的输入
A-算法本身
C-算法复杂性
S-空间复杂性
T-时间复杂性
$$
C = F(N, I, A)\\
T = T(N, I)\\
S = S(N, I)\\
$$
### 算法效率的界
包含最大时间效率、最小时间效率、平均时间效率。
![](image/时间效率的界.png)
## 2 函数的渐进的界
### 函数的界定义
设f 和g 是定义域为自然数集N上的函数
1. $f(n)=O(g(n))$渐进上界
若存在正数$c$和$n0$使得对一切$n≥n0有0≤f(n)≤cg(n)$
2. $f(n)= Ω(g(n))$渐进下届
若存在正数$c$和$n0$使得对一切$n≥n0有0≤cg(n)≤ f(n)$
3. $f(n)=o(g(n))$
对任意正数$c$存在$n0$使得对一切$n≥n0$有$0≤f(n)<cg(n)$
4. $f(n)=ω(g(n))$
对任意正数$c$存在$n0$使得对一切$n≥n0有0≤cg(n)<f(n)$
5. $f(n)=Θ(g(n)) ⇔ f(n)=O(g(n))$ 且$f(n)=Ω(g(n))$紧渐进界
6. $O(1)$表示常数函数
### 函数界的基本性质1
![](image/函数界的基本性质.png)
### 函数界的基本性质2
设f , g, h 是定义域为自然数集N上的函数
1. 如果f =O(g)且g=O(h)那么f =O(h).
2. 如果 f =Ω(g)且g=Ω(h)那么f =Ω(h).
3. 如果f =Θ(g)和g=Θ(h)那么f =Θ(h).
4. O(f(n))+O(g(n)) = O(max{f(n),g(n)})
5. O(f(n))+O(g(n)) = O(f(n)+g(n))
6. O(f(n))*O(g(n)) = O(f(n)*g(n))
### 函数界的基本性质3
1. 设f,g,h 是定义域为自然数集N上的函数若对某个其它的函数h, 我们有f =O(h)和g=O(h)那么f+g = O(h).
2. 假设f 和g是定义域为自然数集合的函数且满足g=O(f)那么f+g=Θ(f).
## 3 算法的基本复杂性类型
### 复杂性分析的基本步骤
1. 决定表示输入规模的参数。
2. 找出算法的基本操作。
3. 检查基本操作的执行次数是否只依赖于输入规模。如果还依赖于输入的其它特性,考虑最差、平均以及最优情况下的复杂性。
4. 对于非递归算法,建立算法基本操作执行次数的求和表达式;对于递归算法,建立算法基本操作执行次数的递推关系及其初始条件。
5. 利用求和公式和法则建立一个操作次数的闭合公式,或者求解递推关系式,确定增长的阶。
## 5 非递归算法的复杂性分析
1. 算法输入规模可以用数组元素个数n度量
2. 基本操作:比较与赋值两种,选择比较
3. 比较操作只与输入规模相关,不用考虑最坏、平均、最好情况
4. 建立基本操作执行次数求和表达式
5. 确定增长的阶
## 6 递归算法的复杂性分析
![](image/递归算法复杂性1.png)
![](image/递归算法复杂性2.png)
![](image/递归算法复杂性3.png)
## 7 递归算法与非递归算法比较
## 8 经验分析方法
## 9 算法可视化
## 10 常见算法算法效率总结
### 比较排序算法
![](image/比较排序算法复杂度.png)
### 排列问题-分治法
![](image/比较排序算法复杂度.png)
### 矩阵乘法-分治法
![](image/矩阵乘法复杂度.png)
二分查找
O(logn)
01背包问题
动态规划O(nc)
回溯法O(2^n)
分支限界O(2^n)
投资问题动态规划O(mn2)
流水作业调度动态规划Johnson 算法O(nlogn)
最大字段和-动态规划O(n)
电路布线问题-动态规划O(n)
图像压缩问题-动态规划O(n)
最长公共子序列-动态规划O(m+n)
N后问题-回溯法O(n^n+1)
活动安排-贪心算法O(nlogn)

View File

@@ -0,0 +1,19 @@
# 分治法
## 1 概述
### 基本思想
将一个难以直接解决的大问题,分解为规模较小的相同子问题,直至这些子问题容易直接求解,并且可以利用这些子问题的解求出原问题的解。各个击破,分而治之。
### 分治法解决问题的先决条件
* 该问题的规模缩小到一定的程度就可以容易地解决;
* 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
* 利用该问题分解出的子问题的解可以合并为该问题的解;
* 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
## 2 具体问题
### 合并排序
基本思想将数组一分为二分别对每个集合单独排序然后将已排序的两个序列归并成一个含n个元素的分好类的序列。如果分割后子问题还很大则继续分治直到只有一个元素。
### 快速排序
基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

View File

@@ -0,0 +1,27 @@
# 动态规划
## 1 概述
### 基本思想
动态规划算法与分治法类似,其思想把求解的问题分成许多阶段或多个子问题,然后按顺序求解各子问题。最后一个阶段或子问题的解就是初始问题的解。
动态规划基本思想是保留已解决的子问题的解,在需要时再查找已求得的解,就可以避免大量重复计算,进而提升算法效率。
要素
### 对比分治法
动态规划中分解得到的子问题不是互相独立的。不同子问题的数目常常只有多项式级,用分治法求解时,有些子问题被重复计算了多次,从而导致分治法求解问题时间复杂度极高。
动态规划的基本思想是保留已经解决的子问题的解。在需要的时候查找已知的解。避免大量重复的计算而提高效率。
### 条件
1. 最优子结构/最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
2. 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
3. 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)
### 基本步骤
1. 找出最优解的性质,刻画其结构特征。
2. 递推地定义最优值
3. 以自底向上的方式计算出最优解。
4. 根据计算最优值时的到的信息,构造最有解。
### 要素
* 最有子结构
* 重叠子问题
* 备忘录方法(矩阵表格)

View File

@@ -0,0 +1,20 @@
# 贪心算法
## 概述
### 思想
贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。
贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。
### 特点
* 贪心算法不能对所有问题都得到整体最优解。但对许多问题他能产生整体最优解,或者最优解的近似。
* 贪心算法中较大子问题的解敲好包含了较小子问题的解作为子集。与动态规划算法中的优化原则本质上一致。
* 动态规划算法在某一步决定优化函数的最大或最小值时,需要考虑他的所有子问题的优化函数的值。然后从中选出最有的结果。贪心算法的每步判断时,不考虑子问题的计算结果,而是根据当前的情况采取“只顾眼前”的贪心策略决定取舍。
### 贪心算法的适用条件
* 最优子结构性质
一个问题的最优解包含其子问题的最优解。问题具有最优子结构性质时,可以用动态规划算法或者贪心算法求解。
### 贪心选择性质
* 所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。
* 动态规划算法通常是自底向上的方式来求解各个子问题。贪心算法同行一自顶向下的方式,一迭代的方式作出相机的谈心选择。每左慈谈心选择就将所求问题简化为规模更小的子问题。
* 对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所做的贪心选择最终导致问题的整体最优解。

View File

@@ -0,0 +1,96 @@
# 回溯法
## 1 概述
### 基本思想
回溯法是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。回溯法的基本思想:该方法系统地搜索一个问题的所有的解或任一解。
### 要素
* 问题解的表示:
回溯法将问题的解表示成n元式。
* 显示约束:
对分量xi的取值限定。
* 隐式约束:
对满足问题的解而对不同分量之间施加约束
* 解空间:
对于一个实例,解向量满足显示约束条件的所有多元组,构成了该实例的一个解空间。
### 基本方法:
明确定义问题的解空间,将问题的解空间组织成树的结构,通过采用系统的方法隐含搜索解空间树,从而得到问题解。回溯法的基本做法是搜索,是一种组织的井井有条的,能避免不必要搜索的穷举式搜索。搜索策略主要有:深度优先、广度优先、函数优先、广度深度结合。
结点分支判定条件:
* 满足约束条件:分之扩展解向量。
* 不满足约束条件:回溯到当前节点的父结点。
结点状态:
* 白结点:尚未访问的节点
* 灰节点:正在访问以该节点为跟的子树。
* 黑节点:以该节点为根的子树遍历完成。
存储当前索索路径
搜索策略(避免无效搜索)
* 约束函数:在扩展节点处减去不满足约束条件的子树。
* 界限函数:在扩展节点处减去得不到最优解的子树。
### 回溯法的适用条件
适用于搜索问题和优化问题
必要条件
* 多米诺性质:叶子节点的解一定满足其父节点。叶子结点为真则父节点一定为真。同理父节点为假则叶子结点一定为假(逆否命题)。用父节点为假的情况进行剪枝操作。
设P(x1,x2,…,xi)是关于向量<x1,x2,…,xi>的某个性质那么P(x1,x2,…,xi+1)真蕴含P(x1,x2,…,xi) 为真,即
P(x1,x2,…,xi+1) → P(x1,x2,…,xi) (0<i<n) (n为向量维数)
### 具体的步骤
1. 针对问题定义解空间
* 问题解向量
* 解向量分量取值集合
* 构造解空间树
2. 判断问题是否满足多米诺性质
3. 搜索解空间树,确定剪枝函数
4. 确定存储搜索路径的数据结构
### 两种典型的解空间树
* 子集树当所给的问题是从n个元素的集合S中找出满足某种性质的子集时相应的解空间树称为子集树。
* 排列树当所给的问题是确定n个元素满足某种性质的排列时相应的解空间成为排列树。排列树有n个叶结点。
问题所有可行解分布在集合{<x1, x2, …, xn> | 1 ≤ xi ≤N, 1 ≤ i ≤N}(解空间)之中。可将问题解空间表示为一定的结构,通过对解空间的搜索,得到满足要求的问题解。
### 回溯法的程序结构
* 递归回溯
```
void backtrack (int t)
{
if (t>n) output(x);
else
for (int i=f(n,t);i<=g(n,t);i++) {
x[t]=h(i);
if (constraint(t)&&bound(t)) backtrack(t+1);
}
}
```
* 迭代回溯
```
void iterativeBacktrack ()
{
int t=1;
while (t>0) {
if (f(n,t)<=g(n,t))
for (int i=f(n,t);i<=g(n,t);i++) {
x[t]=h(i);
if (constraint(t)&&bound(t)) {
if (solution(t)) output(x);
else t++;}
}
else t--;
}
}
```
### 分支限界与回溯法对比
* 求解目标不同:回溯法的求解目标是找出解空间树中满足约束条件的所有解。而分支限界的求解目标是找出满足约束条件的一个解。这个解可能是最优解。
* 搜索方式不同:回溯法以深度优先的方式搜索解空间。而分支限界法则以广度优先或以最小消耗优先的方式搜索解空间。

View File

@@ -0,0 +1,13 @@
# 分支限界
## 1 概述
### 基本思想
在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。
### 常见的两种分支界限法
* 队列式(FIFO)分支限界法按照队列先进先出FIFO原则选取下一个节点为扩展节点。
* 优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,9 @@
# 课程概要
对于不同类别的算法说明。
* A类基本算法
* B类基于特殊数据结构的算法图算法、树算法、堆栈算法这一类应该属于数据结构部分。
* C类特殊算法