C++算法恢复训练之时间复杂度
时间复杂度是算法分析中用于衡量算法运行时间的指标。它表示算法运行所需时间与输入规模之间的关系。通常用大O符号来表示算法的时间复杂度,例如 O ( n ) O(n) O(n)、 O ( n 2 ) O(n^2) O(n2)等。
文章目录
- 一、时间复杂度的表示方法
- 二、那么如何去计算算法的时间复杂度?
- 三、简单算法和算法复杂度的计算
- 总结
一、时间复杂度的表示方法
如果一个算法的时间复杂度是 O ( f ( n ) ) O(f(n)) O(f(n)),那么当输入规模为 n n n时,该算法的运行时间最多是 f ( n ) f(n) f(n)的某个常数倍,即存在正常数 c c c和 n 0 n_0 n0,使得当 n > = n 0 n>=n_0 n>=n0时,算法的运行时间不超过 c ∗ f ( n ) c*f(n) c∗f(n)。
常见的时间复杂度包括:
- 常数时间复杂度 O ( 1 ) O(1) O(1),表示算法的运行时间与输入规模无关;
- 线性时间复杂度 O ( n ) O(n) O(n),表示算法的运行时间与输入规模成线性关系;
- 对数时间复杂度 O ( l o g n ) O(log n) O(logn),表示算法的运行时间与输入规模的对数成正比;
- 平方时间复杂度 O ( n 2 ) O(n^2) O(n2),表示算法的运行时间与输入规模的平方成正比;
- 指数时间复杂度 O ( 2 n ) O(2^n) O(2n),表示算法的运行时间与输入规模的指数成正比。
在实际应用中,我们通常希望算法的时间复杂度越小越好,因为这意味着算法的运行时间更短,更高效。但是,在设计算法时,我们还需要综合考虑其他因素,如空间复杂度、可读性、可维护性等。
二、那么如何去计算算法的时间复杂度?
计算算法的时间复杂度需要分析算法的每个操作在最坏情况下的执行次数,并将这些执行次数相加得到总的时间复杂度。
算法复杂度本质上是一个算法开发人员互相之间交流和评价用的工具,其核心不在于将所有的指令执行次数统计出来。算法复杂度可以视作常数操作的倍数(常数操作,即前文提到的 O ( 1 ) O(1) O(1),可以看作是程序算法执行的最小可统计单元),借助数学中多项式的概念,算法复杂度可以用下面表达式来表示:
f ( x ) = a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n f(x) = a_0 +a_1 x+a_2 x^2+⋯+a_n x^n f(x)=a0+a1x+a2x2+⋯+anxn
诚然,通过分析工具确实可以统计某个常数操作在某次运行过程中的执行次数,但是算法复杂度的意义并不在此。算法工程师们希望用一个更加通用的描述来赋予自己的创作。所以我们也可以看到并没有人会用完整的多项式来“精确”描述自己算法的复杂度,约定的做法是:去除低阶项和常数项,省略高阶项的非零常数系数。
此外,在具体的算法分析时也会遇到一些特定的情况。下面介绍两种常见情况的处理方法。
- 最坏时间复杂度分析法
最坏时间复杂度是指算法在最坏情况下所需的时间。在分析算法时间复杂度时,通常采用最坏时间复杂度分析法。
具体步骤为:
- 找出算法中时间复杂度最高的那条语句;
- 确定语句执行的次数和输入规模的关系;
- 忽略常数项和低次幂项,得到最高次幂的项。
- 例如,下面是一个计算n个元素的数组中最大值的算法:
max = a[0];
for (i = 1; i < n; i++) {
if (a[i] > max) {
max = a[i];
}
}
在该算法中,最耗时的操作是比较大小的if
语句。该语句在最坏情况下会执行n-1次,因此该算法的时间复杂度为
O
(
n
)
O(n)
O(n)。
- 平均时间复杂度分析法
平均时间复杂度是指算法在平均情况下所需的时间。对于一些特殊的算法,如随机算法,采用平均时间复杂度分析法更为合适。
具体步骤为:
- 分析算法中每个操作在所有可能的输入中执行的次数;
- 对每个操作的执行次数进行加权平均,得到平均执行次数;
- 忽略常数项和低次幂项,得到最高次幂的项。
需要注意的是,平均时间复杂度的分析比较复杂,通常需要对算法的输入做出一些假设,如元素是均匀分布的等。
总之,计算算法的时间复杂度需要对算法的每个操作进行分析,并将所有操作的执行次数相加得到总的时间复杂度。计算时间复杂度不仅有助于评估算法的效率,还有助于我们更好地理解和优化算法。
三、简单算法和算法复杂度的计算
课题需求:已知有 有序数组A(大小为n),无序数组B(大小为m),找出B中所有不在A中的数。
- 算法设计1:遍历B中的数,并在A中也通过遍历去判断是否在A中出现;
- 算法设计2:遍历B中的数,并在A中通过二分查找的方式判断是否在A中出现;
- 算法设计3:利用哈希表遍历存储A的所有数,再遍历B中的数,检查哈希表中是否含有该数。
对于算法1,比较容易得出:这个比对的过程需要经历 m ∗ n m*n m∗n次,所以其算法复杂度为 O ( m ∗ n ) O(m*n) O(m∗n)。
对于算法2,二分查找的算法复杂度为 O ( l o g 2 ( n ) ) O(log_2(n)) O(log2(n))(对于长度为n的数组,不断得除以2,需要 l o g 2 ( n ) log_2(n) log2(n)次才能除尽),相当于B里的每个数都要经历 l o g 2 ( n ) log_2(n) log2(n)次才能得出其匹配结果(最坏情况下,对应前面提到的算法计算方法的最坏时间复杂度分析法),所以共计 m ∗ l o g 2 ( n ) m* log_2(n) m∗log2(n),算法复杂度即为 O ( m ∗ l o g 2 ( n ) ) O(m* log_2(n)) O(m∗log2(n))。
对于算法3,因为本身哈希表的查找效率极高,可以看作是常数操作 O ( 1 ) O(1) O(1),所以实际上的执行次数主要是两次遍历,即最后的算法复杂度为 O ( m + n ) O(m+n) O(m+n)。当然这里利用了辅助哈希表,算是额外的空间开销,需要计入空间复杂度的计算。
总结
当涉及到算法设计时,我们需要考虑两个方面:时间复杂度和空间复杂度。
时间复杂度是指算法解决问题所需的时间,即执行算法的指令次数。通常用大O记法表示,可以帮助我们快速了解算法的时间复杂度和问题规模之间的关系。
空间复杂度是指算法解决问题所需的内存空间,即算法运行时占用的内存空间大小。通常用大O记法表示,可以帮助我们快速了解算法的空间复杂度和问题规模之间的关系。
在算法设计中,我们需要在满足问题需求的前提下,尽可能地提高算法的效率,即使得算法的时间复杂度和空间复杂度都尽可能地低。
在分析算法复杂度时,我们需要了解不同算法的复杂度级别,这样可以帮助我们快速判断算法的效率。一般而言,复杂度级别越低,算法效率越高。
最后,算法复杂度是算法设计中非常重要的概念,对于编写高效、快速的算法具有重要意义。在实际应用中,我们需要根据具体问题和应用场景来选择不同的算法,以提高算法的效率和性能。