|
|
@ -92,7 +92,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_first_example](time_complexity.assets/time_complexity_first_example.png)
|
|
|
|
![time_complexity_first_example](time_complexity.assets/time_complexity_first_example.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 算法 A, B, C 的时间增长趋势 </p>
|
|
|
|
<p align="center"> Fig. 算法 A, B, C 的时间增长趋势 </p>
|
|
|
|
|
|
|
|
|
|
|
|
相比直接统计算法运行时间,时间复杂度分析的做法有什么好处呢?以及有什么不足?
|
|
|
|
相比直接统计算法运行时间,时间复杂度分析的做法有什么好处呢?以及有什么不足?
|
|
|
|
|
|
|
|
|
|
|
@ -153,7 +153,7 @@ $T(n)$ 是个一次函数,说明时间增长趋势是线性的,因此易得
|
|
|
|
|
|
|
|
|
|
|
|
![asymptotic_upper_bound](time_complexity.assets/asymptotic_upper_bound.png)
|
|
|
|
![asymptotic_upper_bound](time_complexity.assets/asymptotic_upper_bound.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 函数的渐进上界 </p>
|
|
|
|
<p align="center"> Fig. 函数的渐进上界 </p>
|
|
|
|
|
|
|
|
|
|
|
|
本质上看,计算渐进上界就是在找一个函数 $f(n)$ ,**使得在 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别(仅相差一个常数项 $c$ 的倍数)**。
|
|
|
|
本质上看,计算渐进上界就是在找一个函数 $f(n)$ ,**使得在 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别(仅相差一个常数项 $c$ 的倍数)**。
|
|
|
|
|
|
|
|
|
|
|
@ -245,7 +245,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_common_types](time_complexity.assets/time_complexity_common_types.png)
|
|
|
|
![time_complexity_common_types](time_complexity.assets/time_complexity_common_types.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 时间复杂度的常见类型 </p>
|
|
|
|
<p align="center"> Fig. 时间复杂度的常见类型 </p>
|
|
|
|
|
|
|
|
|
|
|
|
!!! tip
|
|
|
|
!!! tip
|
|
|
|
|
|
|
|
|
|
|
@ -375,7 +375,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_constant_linear_quadratic](time_complexity.assets/time_complexity_constant_linear_quadratic.png)
|
|
|
|
![time_complexity_constant_linear_quadratic](time_complexity.assets/time_complexity_constant_linear_quadratic.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 常数阶、线性阶、平方阶的时间复杂度 </p>
|
|
|
|
<p align="center"> Fig. 常数阶、线性阶、平方阶的时间复杂度 </p>
|
|
|
|
|
|
|
|
|
|
|
|
以「冒泡排序」为例,外层循环 $n - 1$ 次,内层循环 $n-1, n-2, \cdots, 2, 1$ 次,平均为 $\frac{n}{2}$ 次,因此时间复杂度为 $O(n^2)$ 。
|
|
|
|
以「冒泡排序」为例,外层循环 $n - 1$ 次,内层循环 $n-1, n-2, \cdots, 2, 1$ 次,平均为 $\frac{n}{2}$ 次,因此时间复杂度为 $O(n^2)$ 。
|
|
|
|
|
|
|
|
|
|
|
@ -454,7 +454,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_exponential](time_complexity.assets/time_complexity_exponential.png)
|
|
|
|
![time_complexity_exponential](time_complexity.assets/time_complexity_exponential.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 指数阶的时间复杂度 </p>
|
|
|
|
<p align="center"> Fig. 指数阶的时间复杂度 </p>
|
|
|
|
|
|
|
|
|
|
|
|
在实际算法中,指数阶常出现于递归函数。例如以下代码,不断地一分为二,分裂 $n$ 次后停止。
|
|
|
|
在实际算法中,指数阶常出现于递归函数。例如以下代码,不断地一分为二,分裂 $n$ 次后停止。
|
|
|
|
|
|
|
|
|
|
|
@ -516,7 +516,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_logarithmic](time_complexity.assets/time_complexity_logarithmic.png)
|
|
|
|
![time_complexity_logarithmic](time_complexity.assets/time_complexity_logarithmic.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 对数阶的时间复杂度 </p>
|
|
|
|
<p align="center"> Fig. 对数阶的时间复杂度 </p>
|
|
|
|
|
|
|
|
|
|
|
|
与指数阶类似,对数阶也常出现于递归函数。以下代码形成了一个高度为 $\log_2 n$ 的递归树。
|
|
|
|
与指数阶类似,对数阶也常出现于递归函数。以下代码形成了一个高度为 $\log_2 n$ 的递归树。
|
|
|
|
|
|
|
|
|
|
|
@ -577,7 +577,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_logarithmic_linear](time_complexity.assets/time_complexity_logarithmic_linear.png)
|
|
|
|
![time_complexity_logarithmic_linear](time_complexity.assets/time_complexity_logarithmic_linear.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 线性对数阶的时间复杂度 </p>
|
|
|
|
<p align="center"> Fig. 线性对数阶的时间复杂度 </p>
|
|
|
|
|
|
|
|
|
|
|
|
### 阶乘阶 $O(n!)$
|
|
|
|
### 阶乘阶 $O(n!)$
|
|
|
|
|
|
|
|
|
|
|
@ -618,7 +618,7 @@ $$
|
|
|
|
|
|
|
|
|
|
|
|
![time_complexity_factorial](time_complexity.assets/time_complexity_factorial.png)
|
|
|
|
![time_complexity_factorial](time_complexity.assets/time_complexity_factorial.png)
|
|
|
|
|
|
|
|
|
|
|
|
<p style="text-align:center"> Fig. 阶乘阶的时间复杂度 </p>
|
|
|
|
<p align="center"> Fig. 阶乘阶的时间复杂度 </p>
|
|
|
|
|
|
|
|
|
|
|
|
## 最差、最佳、平均时间复杂度
|
|
|
|
## 最差、最佳、平均时间复杂度
|
|
|
|
|
|
|
|
|
|
|
|