第一部分:为什么要分析算法?(核心思想)
我们评价一个算法的好坏,主要看两个方面:
- 时间效率:算法运行需要多长时间?
- 空间效率:算法运行需要多少内存?
一个好的算法,应该是在满足正确性的前提下,跑得快、占内存少。算法分析的实质,就是提前预估一个算法在时间和空间上的开销,从而帮助我们选择最优的解决方案。
第二部分:如何衡量算法效率?
我们有两种方法来衡量算法的效率。
1. 事后统计法 (Post-hoc Analysis)
- 做法:先把算法用编程语言实现,然后在计算机上运行,通过计时函数(如C++的
clock())来测量其运行时间。 - 优点:非常直观,能看到确切的执行时间。
- 缺点:
- 太麻烦:需要先编写程序。
- 依赖环境:结果受计算机硬件、操作系统、编程语言等多种因素影响。在你的电脑上跑5秒,在考试的电脑上可能跑10秒。
- 数据选择难:用什么规模的数据来测试?数据量太小看不出差别,太大又可能要等很久。
- 结论:这种方法不适合作为理论分析工具,通常只用于验证或在特定环境下做性能评测。
2. 事前分析估算法 (A-priori Analysis)
这是我们在考试和理论分析中 唯一使用 的方法。
- 做法:在不编写程序的情况下,通过分析算法的逻辑结构,估算出其“工作量”。
- 核心思想:一个算法的执行时间,取决于其中所有语句执行次数的总和。我们不关心具体的一条语句执行需要多少微秒,而是关心它被执行了多少次。
第三部分:时间复杂度 (Time Complexity) - 笔试核心
时间复杂度是衡量算法时间效率最重要的概念。
1. 基本概念
- 问题规模 (n):影响算法工作量的数据大小。例如,对一个数组排序,
n就是数组的长度;计算 1+2+...+n1+2+...+n1+2+...+n,n就是那个数字n。 - 语句频率:一条语句在算法中被重复执行的次数。
- 基本运算:算法中处于最内层循环、执行次数最多的核心操作。我们通常用基本运算的执行次数来代表整个算法的工作量。
2. 时间复杂度 T(n)
我们把算法中 基本运算的执行次数 定义为该算法的时间复杂度,记为 T(n)T(n)T(n)。T(n)T(n)T(n) 是问题规模 nnn 的函数。
示例1:计算 1+2+...+n1+2+...+n1+2+...+n
-
算法一 (循环相加)
int sum = 0; for (int i = 1; i <= n; i++) { sum += i; // 这是基本运算 }sum += i;这条语句被执行了n次。所以,T(n)=nT(n) = nT(n)=n。 -
算法二 (数学公式)
int sum = n * (n + 1) / 2; // 乘、加、除都是基本运算无论
n多大,这个公式都只执行1次。所以,T(n)=1T(n) = 1T(n)=1。
显而易见,算法二的效率远高于算法一。
3. 最坏、最好和平均时间复杂度
有时,算法的执行时间不仅与问题规模 n 有关,还与输入数据的具体内容有关。
示例:在一个长度为n的数组R中查找元素K
for (int i = 0; i < n; i++) {
if (R[i] == K) {
return i; // 找到了
}
}
return -1; // 没找到
- 最好情况 (Best Case):运气爆棚,第一个元素就是K。比较1次。B(n)=1B(n) = 1B(n)=1。
- 最坏情况 (Worst Case):运气最差,最后一个元素才是K,或者根本不存在K。需要比较
n次。W(n)=nW(n) = nW(n)=n。 - 平均情况 (Average Case):假设K在数组中每个位置出现的概率相同,计算其数学期望。E(n)=(n+1)/2E(n) = (n+1)/2E(n)=(n+1)/2。
在考试和实际分析中,我们通常最关心的是“最坏情况时间复杂度”,因为它为算法的性能提供了一个保证,告诉我们算法运行时间的上限。
第四部分:渐进时间复杂度 (Asymptotic Time Complexity) - 笔试和机试的关键
当问题规模 n 变得非常大时,我们不再关心 T(n)T(n)T(n) 的具体表达式中的常数项或低次项,只关心其 增长趋势。这就是渐进复杂度的思想。
1. 大O表示法 (Big O Notation)
我们使用大O表示法来描述算法的渐进时间复杂度。它表示算法时间复杂度的 上界。
- 定义:若存在正常数 CCC 和 n0n_0n0,使得对于所有 n≥n0n \ge n_0n≥n0,都有 T(n)≤C⋅g(n)T(n) \le C \cdot g(n)T(n)

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



