数据结构和算法

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 施特拉森矩阵乘法 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 快速指南


数据结构 - 渐近分析


渐近分析

算法的渐近分析是指定义其运行时性能的数学基础/框架。利用渐近分析,我们可以很好地推导出算法的最佳情况、平均情况和最坏情况。

渐近分析是输入受限的,即如果算法没有输入,则推断其运行时间为常数。除"输入"外,所有其他因素均视为常数。

渐近分析是指以数学计算单位计算任何操作的运行时间。例如,一个操作的运行时间计算为 f(n),而另一个操作的运行时间计算为 g(n2)。这意味着第一个操作的运行时间将随着 n 的增加而线性增加,而第二个操作的运行时间将随着 n 的增加而呈指数增加。同样,如果 n 非常小,则两个操作的运行时间将几乎相同。

通常,算法所需的时间分为三种类型 −

  • 最佳情况 − 程序执行所需的最短时间。

  • 平均情况 − 程序执行所需的平均时间。

  • 最坏情况 −程序执行所需的最大时间。

渐近符号

算法的执行时间取决于指令集、处理器速度、磁盘 I/O 速度等。因此,我们用渐近的方式估计算法的效率。

算法的时间函数用 T(n) 表示,其中 n 是输入的大小。

不同类型的渐近符号用于表示算法的复杂度。以下渐近符号用于计算算法的运行时间复杂度。

  • O − 大 O 符号

  • Ω −大 Omega 符号

  • θ − 大 Theta 符号

  • o − 小 Omega 符号

  • ω − 小 Omega 符号

​​大 O,O:渐近上界

符号 Ο(n) 是表示算法运行时间上限的正式方式。是最常用的符号。它衡量的是最坏情况的时间复杂度,即算法完成所需的最长时间。

如果存在正整数n的值为n0,并且存在正常数c,使得−

,则函数f(n)可以表示为g(n)的阶,即O(g(n))。

当$n > n_{0}$时,$f(n)\leqslant c.g(n)$始终成立

因此,函数g(n)是函数f(n)的上限,如下所示g(n) 的增长速度比 f(n) 快。

Big Oh Notation

示例

考虑一个给定函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$

设 $g(n) = n^3$,

对于所有 $n > 2$ 的值,$f(n)\leqslant 5.g(n)$

因此,f(n) 的复杂度可以表示为 $O(g(n))$,即 $O(n^3)$

​​大欧米茄,Ω:渐近下界

符号Ω(n) 是表示算法运行时间下界的正式方式。它衡量的是最佳情况的时间复杂度,即算法完成所需的最佳时间。

当存在常数c,使得对于所有足够大的n值,$f(n)\geqslant c.g(n)$时,我们称 $f(n) = \Omega (g(n))$。其中n为正整数。这意味着函数g是函数f的下界;在 n> 达到某个值之后,f 永远不会低于 g。

omega notation

示例

考虑一个给定函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$。

设 $g(n) = n^3$,则对于所有 $n > 0$ 的值,$f(n)\geqslant 4.g(n)$。

因此,f(n) 的复杂度可以表示为 $\Omega (g(n))$,即 $\Omega (n^3)$。

​​Theta,θ:渐近紧界

符号 θ(n) 是表示算法运行时间下限和上限的正式方式。有些人可能会将 Theta 符号与平均情况的时间复杂度混淆;虽然大 Theta 符号可以几乎准确地用于描述平均情况,但也可以使用其他符号。

当存在常数 c1 和 c2,使得对于所有足够大的 n 值,$c_{1}.g(n) \leqslant f(n) \leqslant c_{2}.g(n)$ 时,我们称 $f(n) = heta(g(n))$。这里 n 是一个正整数。

这意味着函数 g 是函数 f 的紧界。

theta notation

示例

考虑一个给定函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$

设 $g(n) = n^3$,对于 n 的所有较大值,$4.g(n) \leqslant f(n) \leqslant 5.g(n)$。

因此,f(n) 的复杂度可以表示为 $heta(g(n))$,即 $heta(n^3)$。

小 Oh, o

O-notation 提供的渐近上界可能渐近紧,也可能不渐近紧。上界 $2.n^2 = O(n^2)$ 是渐近紧的,但上界 $2.n = O(n^2)$ 却不是。

我们使用 o-符号 来表示非渐近紧的上界。

我们正式定义 o(g(n))(n 的 g 的小 oh)为集合 f(n) = o(g(n)),其中任意正常数 $c > 0$,存在一个值 $n_{0} > 0$,使得 $0 \leqslant f(n) \leqslant c.g(n)$。

直观地,在 o-符号 中,函数 f(n) 相对于g(n) 当 n 趋近于无穷大时;即:

$$\lim_{n ightarrow \infty}\left(\frac{f(n)}{g(n)} ight) = 0$$

示例

考虑同一个函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$

设 $g(n) = n^{4}$,

$$\lim_{n ightarrow \infty}\left(\frac{4.n^3 + 10.n^2 + 5.n + 1}{n^4} ight) = 0$$

因此,f(n)的复杂度可以表示为 $o(g(n))$,即: $o(n^4)$。

小 Omega,ω

我们使用 ω-notation 来表示非渐近紧的下界。然而,正式地,我们将 ω(g(n))(n 的 g 的小 Omega)定义为集合 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} eq \omega (n^2)$。关系 $f(n) = \omega (g(n))$ 意味着存在以下极限

$$\lim_{n ightarrow \infty}\left(\frac{f(n)}{g(n)} ight) = \infty$$

也就是说,当 n 趋于无穷大时,f(n) 相对于 g(n) 变得任意大。

示例

考虑同一个函数,$f(n) = 4.n^3 + 10.n^2 + 5.n + 1$

设 $g(n) = n^2$,

$$\lim_{n ightarrow \infty}\left(\frac{4.n^3 + 10.n^2 + 5.n + 1}{n^2} ight) = \infty$$

因此,f(n) 的复杂度可以表示为 $o(g(n))$,即 $\omega (n^2)$。

常见渐近符号

以下列出了一些常见的渐近符号 −

constant − O(1)
logarithmic − O(log n)
linear − O(n)
n log n − O(n log n)
quadratic − O(n2)
cubic − O(n3)
polynomial − nO(1)
exponential − 2O(n)

Apriori 和 Apostiari 分析

Apriori 分析是指在特定系统上运行之前进行分析。此分析是使用某些理论模型定义函数的阶段。因此,我们只需查看算法本身,即可确定其时间和空间复杂度,而无需在具有不同内存、处理器和编译器的特定系统上运行它。

算法的 Apostiari 分析是指我们仅在系统上运行算法后才对其进行分析。它直接依赖于系统,并且会因系统而异。

在工业界,我们无法进行 Apostiari 分析,因为软件通常是为匿名用户开发的,而匿名用户会在与工业界不同的系统上运行该软件。

在 Apriori 分析中,我们使用渐近符号来确定时间和空间复杂度,因为它们在不同计算机中有所不同;然而,它们的渐近性是相同的。