- 数据结构与算法
- DSA - 首页
- DSA - 概述
- DSA - 环境设置
- DSA - 算法基础
- DSA - 渐近分析
- 数据结构
- DSA - 数据结构基础
- DSA - 数据结构和类型
- DSA - 数组数据结构
- 链表
- DSA - 链表数据结构
- DSA - 双向链表数据结构
- DSA - 循环链表数据结构
- 栈与队列
- DSA - 栈数据结构
- DSA - 表达式解析
- DSA - 队列数据结构
- 搜索算法
- DSA - 搜索算法
- DSA - 线性搜索算法
- DSA - 二分搜索算法
- DSA - 插值搜索
- DSA - 跳跃搜索算法
- DSA - 指数搜索
- DSA - 斐波那契搜索
- DSA - 子列表搜索
- DSA - 哈希表
- 排序算法
- DSA - 排序算法
- DSA - 冒泡排序算法
- DSA - 插入排序算法
- DSA - 选择排序算法
- DSA - 归并排序算法
- DSA - 希尔排序算法
- DSA - 堆排序
- DSA - 桶排序算法
- DSA - 计数排序算法
- DSA - 基数排序算法
- DSA - 快速排序算法
- 图数据结构
- DSA - 图数据结构
- DSA - 深度优先遍历
- DSA - 广度优先遍历
- DSA - 生成树
- 树数据结构
- DSA - 树数据结构
- DSA - 树遍历
- DSA - 二叉搜索树
- DSA - AVL树
- DSA - 红黑树
- DSA - B树
- DSA - B+树
- DSA - 伸展树
- DSA - 字典树
- DSA - 堆数据结构
- 递归
- DSA - 递归算法
- DSA - 使用递归实现汉诺塔
- DSA - 使用递归实现斐波那契数列
- 分治法
- DSA - 分治法
- DSA - 最大最小问题
- DSA - Strassen矩阵乘法
- DSA - Karatsuba算法
- 贪心算法
- DSA - 贪心算法
- DSA - 旅行商问题(贪心算法)
- DSA - Prim最小生成树
- DSA - Kruskal最小生成树
- DSA - Dijkstra最短路径算法
- DSA - 地图着色算法
- DSA - 分数背包问题
- DSA - 带截止日期的作业排序
- DSA - 最优合并模式算法
- 动态规划
- DSA - 动态规划
- DSA - 矩阵链乘法
- DSA - Floyd-Warshall算法
- DSA - 0-1背包问题
- DSA - 最长公共子序列算法
- DSA - 旅行商问题(动态规划)
- 近似算法
- DSA - 近似算法
- DSA - 顶点覆盖算法
- DSA - 集合覆盖问题
- DSA - 旅行商问题(近似算法)
- 随机化算法
- DSA - 随机化算法
- DSA - 随机化快速排序算法
- DSA - Karger最小割算法
- DSA - Fisher-Yates洗牌算法
- DSA有用资源
- DSA - 问答
- DSA - 快速指南
- DSA - 有用资源
- DSA - 讨论
数据结构 - 渐近分析
渐近分析
算法的渐近分析是指定义其运行时间性能的数学基础/框架。使用渐近分析,我们可以很好地得出算法的最佳情况、平均情况和最坏情况。
渐近分析是输入相关的,即如果算法没有输入,则认为其在常数时间内完成。除“输入”外,所有其他因素都被认为是常数。
渐近分析是指用数学计算单位计算任何操作的运行时间。例如,一个操作的运行时间计算为f(n),而另一个操作的运行时间计算为g(n2)。这意味着第一个操作的运行时间将随着n的增加而线性增加,而第二个操作的运行时间将随着n的增加而呈指数增加。类似地,如果n非常小,则两个操作的运行时间将大致相同。
通常,算法所需的时间分为三种类型:
最佳情况 - 程序执行所需的最小时间。
平均情况 - 程序执行所需的平均时间。
最坏情况 - 程序执行所需的最多时间。
渐近记号
算法的执行时间取决于指令集、处理器速度、磁盘I/O速度等。因此,我们渐近地估计算法的效率。
算法的时间函数用T(n)表示,其中n是输入大小。
不同类型的渐近记号用于表示算法的复杂性。以下渐近记号用于计算算法的运行时间复杂性。
O - 大O记号
Ω - 大Ω记号
θ - 大θ记号
o - 小o记号
ω - 小ω记号
大O,O:渐近上界
记号Ο(n)是表示算法运行时间上界的正式方法。是最常用的记号。它衡量最坏情况时间复杂度或算法可能完成所需的最长时间。
如果存在正整数n的值为n0和正常数c,则函数f(n)可以表示为g(n)的阶,即O(g(n)),使得:
$f(n)\leqslant c.g(n)$ 对于所有情况下的$n > n_{0}$
因此,函数g(n)是函数f(n)的上界,因为g(n)的增长速度快于f(n)。
示例
让我们考虑一个给定的函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$
考虑$g(n) = n^3$,
$f(n)\leqslant 5.g(n)$ 对于所有$n > 2$的值
因此,f(n)的复杂度可以表示为$O(g(n))$,即$O(n^3)$
大Ω,Ω:渐近下界
记号Ω(n)是表示算法运行时间下界的正式方法。它衡量最佳情况时间复杂度或算法可能完成所需的最短时间。
当存在常数c使得$f(n)\geqslant c.g(n)$对于所有足够大的n值成立时,我们说$f(n) = \Omega (g(n))$。这里n是正整数。这意味着函数g是函数f的下界;在某个n值之后,f永远不会低于g。
示例
让我们考虑一个给定的函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$。
考虑$g(n) = n^3$,$f(n)\geqslant 4.g(n)$对于所有$n > 0$的值。
因此,f(n)的复杂度可以表示为$\Omega (g(n))$,即$\Omega (n^3)$
θ,θ:渐近紧界
记号θ(n)是表示算法运行时间上下界的正式方法。有些人可能会将θ记号误认为是平均情况时间复杂度;虽然大θ记号可以几乎准确地用于描述平均情况,但也可以使用其他记号。
当存在常数c1和c2使得$c_{1}.g(n) \leqslant f(n) \leqslant c_{2}.g(n)$对于所有足够大的n值成立时,我们说$f(n) = \theta(g(n))$。这里n是正整数。
这意味着函数g是函数f的紧界。
示例
让我们考虑一个给定的函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$
考虑$g(n) = n^3$,$4.g(n) \leqslant f(n) \leqslant 5.g(n)$对于所有较大的n值。
因此,f(n)的复杂度可以表示为$\theta (g(n))$,即$\theta (n^3)$。
小o,o
O-记号提供的渐近上界可能是也可能不是渐近紧密的。界限$2.n^2 = O(n^2)$是渐近紧密的,但界限$2.n = O(n^2)$不是。
我们使用o-记号来表示不是渐近紧密的界限。
我们正式定义o(g(n))(g(n)的小o)为集合f(n) = o(g(n)),对于任何正常数$c > 0$,都存在一个值$n_{0} > 0$,使得$0 \leqslant f(n) \leqslant c.g(n)$。
直观地说,在o-记号中,当n趋于无穷大时,函数f(n)相对于g(n)变得微不足道;也就是说,
$$\lim_{n \rightarrow \infty}\left(\frac{f(n)}{g(n)}\right) = 0$$
示例
让我们考虑相同的函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$
考虑$g(n) = n^{4}$,
$$\lim_{n \rightarrow \infty}\left(\frac{4.n^3 + 10.n^2 + 5.n + 1}{n^4}\right) = 0$$
因此,f(n)的复杂度可以表示为$o(g(n))$,即$o(n^4)$。
小ω,ω
我们使用ω-记号来表示不是渐近紧密的界限。然而,我们正式定义ω(g(n))(g(n)的小ω)为集合f(n) = ω(g(n)),对于任何正常数C > 0,都存在一个值$n_{0} > 0$,使得$0 \leqslant c.g(n) < f(n)$。
例如,$\frac{n^2}{2} = \omega (n)$,但$\frac{n^2}{2} \neq \omega (n^2)$。关系$f(n) = \omega (g(n))$暗示存在以下极限
$$\lim_{n \rightarrow \infty}\left(\frac{f(n)}{g(n)}\right) = \infty$$
也就是说,当n趋于无穷大时,f(n)相对于g(n)变得任意大。
示例
让我们考虑相同的函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$
考虑$g(n) = n^2$,
$$\lim_{n \rightarrow \infty}\left(\frac{4.n^3 + 10.n^2 + 5.n + 1}{n^2}\right) = \infty$$
因此,f(n)的复杂度可以表示为$o(g(n))$,即$\omega (n^2)$。
常用渐近记号
以下是一些常用渐近记号的列表:
常数 | - | O(1) |
对数 | - | O(log n) |
线性 | - | O(n) |
n log n | - | O(n log n) |
平方 | - | O(n2) |
三次方 | - | O(n3) |
多项式 | - | nO(1) |
指数级 | - | 2O(n) |
先验和后验分析
先验分析是指在算法运行于特定系统之前进行的分析。这种分析阶段使用某种理论模型定义函数。因此,我们只需查看算法本身,无需在具有不同内存、处理器和编译器的特定系统上运行它,即可确定算法的时间和空间复杂度。
算法的后验分析是指仅在系统运行算法之后才进行的分析。它直接依赖于系统,并且会因系统而异。
在行业中,我们无法进行后验分析,因为软件通常是为匿名用户开发的,这些用户会在与行业中存在的系统不同的系统上运行它。
在先验分析中,我们使用渐近符号来确定时间和空间复杂度的原因是,它们会因计算机而异;但是,渐近地它们是相同的。