Algorithms
3.1 算法
算法指导了解决一般性问题的一系列步骤。
- 算法
进行一项计算或解决一个问题的精确指令的有限序列。 - 伪代码(pseudocode)
在算法的中文描述及该算法的一种编程语言实现之间的中间一步。
时间复杂度: Θ ( n ) \Theta (n) Θ(n) - 算法的性质
输入
输出
确定性(准确定义)
正确性(正确的输出值)
有限性(步骤有限)
有效性(有限时间)
通用性(用于期望形式的所有问题) - 线性搜索(顺序搜索)
将 x x x 逐步与 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 相比,直到匹配完成。
时间复杂度: Θ ( n ) \Theta (n) Θ(n)(最坏情形和平均) - 二分搜索
列表各项元素呈升序。
不断比较要搜索的元素与列表的中间项,直到得到只含一项的列表,再进行判断。
时间复杂度: Θ ( log n ) \Theta(\log n) Θ(logn)(最坏情形) - 排序(sorting)
把元素排成一个列表,其中元素按照升序排列。 - 冒泡排序(bubble sort)
连续比较相邻的元素,顺序不对即交换,直至列表为升序。
最坏情形复杂度: Θ ( n 2 ) \Theta(n^2) Θ(n2) - 插入排序(insert sort)
从第二个元素开始,每插入一个元素,从第一个元素开始进行比较,插入到正确的位置。
最坏情形复杂度: Θ ( n 2 ) \Theta(n^2) Θ(n2) - 字符串匹配
在文本(text)(字符串 T T T)中寻找一个模式(pattern)(字符串 P P P)出现的位置。 - 朴素字符串匹配器
字符串匹配的蛮力算法
模式: P = p 1 p 2 . . . p m P=p_1p_2...p_m P=p1p2...pm
文本: T = t 1 t 2 . . . t n T=t_1t_2...t_n T=t1t2...tn
P P P 出现在 T T T 中偏移(shift) s s s处:当模式在在文本 T T T 的第 s + 1 s+1 s+1 个位置开始,即 t s + 1 = p 1 , t s + 2 = p 2 , . . . , t s + m = p m , t_{s+1} = p_1,t_{s+2} = p_2,...,t_{s+m} = p_m, ts+1=p1,ts+2=p2,...,ts+m=pm,
遍历 s = 0 s=0 s=0 到 s = n − m s=n-m s=n−m,判断 s s s 是否是有效偏移。
- 最优化问题(optimization problem)
寻找给定问题满足某个参数值最小化或最大化的解。 - 贪婪算法(greedy algorithm)
在每一步都选择最好的选项,而不是通盘考虑可能导致最优解的全部步骤序列。
如果只用25、10、5和1美分硬币,则该算法总是产生硬币数量最少的找零方案。
根据结束时间的升序来对讲座进行排序。 - 停机问题(halting problem)
询问是否存在一个过程(procedure) 能够:该过程以一个计算机程序以及该程序的一个输入作为输入,并判断该程序在给定输入运行时是否最终能停止。
3.2 函数的增长
运行实现一个算的程序的硬件和软件 → \rightarrow → 算法估算时间乘以一个常数 → \rightarrow → 精确地估算求解规模为n的问题所需的时间
- 大
O
O
O 记号
f f f 和 g g g :从整数集(实数集)到实数集的函数。
f ( x ) f(x) f(x) 是 O ( g ( x ) ) O(g(x)) O(g(x))的:若存在常数 C C C 和 k k k 使得 x > k x>k x>k 时,有 ∣ f ( x ) ∣ ⩽ C ∣ g ( x ) ∣ \mid f(x) \mid \leqslant C \mid g(x) \mid ∣f(x)∣⩽C∣g(x)∣
描述函数的增长:当 x x x 无限增长时 f ( x ) f(x) f(x) 的增长慢于 g ( x ) g(x) g(x) 的某个固定的倍数。
常数 C C C 和 k k k : f ( x ) f(x) f(x) 是 O ( g ( x ) ) O(g(x)) O(g(x))的关系的凭证(witness)。 - 多项式增长的估算
令 f ( x ) = a n x n + a n − 1 x n − 1 + . . . + a 1 x + x 0 f(x) = a_nx^n+a_{n-1}x^{n-1}+...+a_1x+x_0 f(x)=anxn+an−1xn−1+...+a1x+x0, a 0 , a 1 , . . . , a n − 1 , a n a_0,a_1,...,a_{n-1},a_n a0,a1,...,an−1,an 为实数,
那么 f ( x ) f(x) f(x) 是 O ( x n ) O(x^n) O(xn) 的。 - 对数、幂、指数函数的大
O
O
O 估算
1 , log n , n , n log n , n 2 , 2 n , n ! 1,\log n,n,n \log n,n^2,2^n,n! 1,logn,n,nlogn,n2,2n,n!
任意一个函数与随后的函数的壁纸在 n n n 无限增长时趋向于0(每个函数都小于随后的函数)。
- 函数和的大
O
O
O估算
f 1 ( x ) f_1(x) f1(x) 是 O ( g 1 ( x ) ) O(g_1(x)) O(g1(x)) 的, f 2 ( x ) f_2(x) f2(x) 是 O ( g 2 ( x ) ) O(g_2(x)) O(g2(x)) 的
则 ( f 1 + f 2 ) ( x ) (f_1+f_2)(x) (f1+f2)(x) 是 O ( g ( x ) ) O(g(x)) O(g(x))的,其中对所有 x x x 有 g ( x ) = ( m a x ( ∣ g 1 ( x ) ∣ , ∣ g 2 ( x ) ∣ ) ) g(x) = (max(\mid g_1(x) \mid ,\mid g_2(x) \mid)) g(x)=(max(∣g1(x)∣,∣g2(x)∣)) - 函数积的估算
f 1 ( x ) f_1(x) f1(x) 是 O ( g 1 ( x ) ) O(g_1(x)) O(g1(x)) 的, f 2 ( x ) f_2(x) f2(x) 是 O ( g 2 ( x ) ) O(g_2(x)) O(g2(x)) 的
那么 ( f 1 f 2 ) ( x ) (f_1f_2)(x) (f1f2)(x) 是 O ( g 1 ( x ) g 2 ( x ) ) O(g_1(x)g_2(x)) O(g1(x)g2(x)) 的 - 大
O
O
O、大
Ω
\Omega
Ω、大
Θ
\Theta
Θ
大 O O O:只可以估算对于大 x x x值的 f ( x ) f(x) f(x)的上限
大 Ω \Omega Ω:只可以估算对于大 x x x值的 f ( x ) f(x) f(x)的下限
大 Θ \Theta Θ:可以给出函数 f ( x ) f(x) f(x) 的相对于参照函数 g ( x ) g(x) g(x) 的上限和下限。 - 大
Ω
\Omega
Ω记号
f f f 和 g g g :从整数集(实数集)到实数集的函数。
f ( x ) f(x) f(x) 是 Ω ( g ( x ) ) \Omega(g(x)) Ω(g(x))的:若存在正常数 C C C 和 k k k 使得 x > k x>k x>k 时,有 ∣ f ( x ) ∣ ⩾ C ∣ g ( x ) ∣ \mid f(x) \mid \geqslant C \mid g(x) \mid ∣f(x)∣⩾C∣g(x)∣ - 大
Θ
\Theta
Θ记号
f f f 和 g g g :从整数集(实数集)到实数集的函数。
f ( x ) f(x) f(x) 是 Θ ( g ( x ) ) \Theta(g(x)) Θ(g(x))的:如果 f ( x ) f(x) f(x) 是 O ( g ( x ) ) O(g(x)) O(g(x))的,并且 f ( x ) f(x) f(x) 是 Ω ( g ( x ) ) \Omega(g(x)) Ω(g(x))的。
此时, f ( x ) f(x) f(x) 是 g ( x ) g(x) g(x) 阶的,或者说 f ( x ) f(x) f(x) 与 g ( x ) g(x) g(x) 同阶。 - 多项式的阶
令 f ( x ) = a n x n + a n − 1 x n − 1 + . . . + a 1 x + x 0 f(x) = a_nx^n+a_{n-1}x^{n-1}+...+a_1x+x_0 f(x)=anxn+an−1xn−1+...+a1x+x0, a 0 , a 1 , . . . , a n − 1 , a n a_0,a_1,...,a_{n-1},a_n a0,a1,...,an−1,an 为实数,且 a n ≠ 0 a_n \neq 0 an=0,
则 f ( x ) f(x) f(x) 是 x n x^n xn 阶的。
3.3 算法的复杂度
-
计算复杂度(computational complexity)
① 当输入值具有一定规模是,计算机按此算法解题花的时间。
② 输入值具有一定规模时,实现这一算法需要多大内存。 -
时间复杂度
解决特定规模的问题所需时间的分析;
用所需运算次数而不是计算机实际使用的时间来表示。 -
空间复杂度
所需计算机内存的分析 -
最坏情形复杂度
算法用于具有一定输入规模的问题时所需要的做多的运算次数。 -
平均情形复杂度
求解针对一定规模的问题的所有可能的输入所用到的运算的平均数。 -
矩阵乘法的复杂度
n 3 n^3 n3次乘法, n 2 ( n − 1 ) n^2(n-1) n2(n−1)次加法。 O ( n 3 ) O(n^3) O(n3) -
矩阵布尔积的算法复杂度
2 n 3 2n^3 2n3 次比特运算 -
矩阵链乘法
矩阵链 A 1 A 2 . . . A n A_1A_2...A_n A1A2...An,其中 A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An 分别为 m 1 × m 2 , m 2 × m 3 , . . . , m n × m n + 1 m_1 \times m_2,m_2 \times m_3,...,m_n\times m_{n+1} m1×m2,m2×m3,...,mn×mn+1 阶的整数矩阵。
把一个 m 1 × m 2 m_1 \times m_2 m1×m2 矩阵和一个 m 2 × m 3 m_2 \times m_3 m2×m3矩阵相乘需要做 m 1 m 2 m 3 m_1m_2m_3 m1m2m3次整数乘法。 -
算法范例(algorithmic paradigm)
是基于一种特定概念的通用方法,可以用来构造求解一类广泛问题的算法。
①贪婪算法
②蛮力算法(brute-force algorithm):通过基于对问题的描述和术语的定义以最直接的方式解决,适合不太在意所需计算资源的问题。
冒泡排序、插入排序、选择排序、矩阵乘法是蛮力算法,适合输入规模不大的问题。
Θ ( n 2 ) \Theta(n^2) Θ(n2) 次操作 -
算法复杂度
常量复杂度
对数复杂度(二分搜索)
线性复杂度(线性搜素)
线性对数复杂度(归并排序)
多项式复杂度(冒泡排序)
指数复杂度
阶乘复杂度
-
易解性(tractability)
一个能用多项式最坏情形复杂度(或更优)的算法求解的问题称为易解的(tractable)。 -
不可解的(unsolvable)
一些问题被证明是没有算法能够求解它们的。 -
P与NP
没有多项式最坏情形时间复杂度的算法求解,但是该问题一旦有了一个解,就能以多项式时间内验证解的问题称为属于NP类(易解的问题属于P类)。
NP(nondeterministic polynomial)——非确定性多项式
NP完全问题(NP-complete problem):只要其中任何一个问题能用多项式时间最坏情形算法来求解,那么NP类的所有问题都能用多项式时间最坏情形算法来求解。 -
P与NP问题(P versus NP problem)
是 问NP是否等于P ?
① 若 P ≠ \neq = NP,则存在一些不能在多项式时间内求解但其解可以在多项式时间内验证的问题。
② 无人成功证明 P = NP。 -
算法时间复杂度
算法时间复杂度经常用大 O O O 估算(最坏情形) ,而不使用大 Θ \Theta Θ 估算。 -
运行算法的所需计算机时间
求解各种输入规模问题所需的时间,用位运算的位数 n n n 表示,假定每次位运算需要的时间是 1 0 − 11 10^{-11} 10−11 秒。