算法笔记
算法是什么
算法(algorithm)就是任何 良定义 的计算过程,该过程取某个值或值的集合作为输入并产生某个值或值的集合作为输出,即是把输入换成输出的计算步骤的一个序列。
算法也可以看成是用于计算问题的工具,即描述一个特定的计算过程来实现问题所期望的输入/输出关系。
算法的特征
- 有穷性(Finiteness):算法的有穷性是指算法必须能在执行有限个步骤之后终止;
- 确定性(Definiteness):算法的每一步骤必须有确切的定义;
- 输入项(Input):一个算法有0个或多个输入,以刻画运算对象的初始情况(所谓0个输入是指算法本身定出了初始条件);
- 输出项(Output):一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
- 可行性(Effectiveness):算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。
算法的评价
时间复杂度
一个算法中的语句最坏情况下执行次数称为语句频度或时间频度,记为 T ( n ) T(n) T(n);
若存在 f ( n ) f(n) f(n),使 lim n − > ∞ T ( n ) f ( n ) \lim_{n->∞}\frac{T(n)}{f(n)} limn−>∞f(n)T(n) 为不等于零的常数,则称 f ( n ) f(n) f(n)为 T ( n ) T(n) T(n)的同数量级(阶)函数,记作
T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n))
称 O ( f ( n ) ) O(f(n)) O(f(n))为算法 T ( n ) T(n) T(n)的渐进时间复杂度,简称时间复杂度。
计算
- 取最大的项
- 省略掉所有的常数系数、常数底数、常数项
渐进符号
Θ Θ Θ记号(渐进紧确界)
对于函数 f ( n ) f(n) f(n) 和 g ( n ) g(n) g(n), f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),当且仅当 ∃ c 1 , c 2 , n 0 > 0 \exist c_1,c_2,n_0>0 ∃c1,c2,n0>0,使得 ∀ n ≥ n 0 , 0 ≤ c 1 ⋅ g ( n ) ≤ f ( n ) ≤ c 2 ⋅ g ( n ) \forall n ≥ n_0,0≤ c_1·g(n) ≤ f(n) ≤ c_2 · g(n) ∀n≥n0,0≤c1⋅g(n)≤f(n)≤c2⋅g(n)。
也就是说,如果函数 f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),那么我们能找到两个正数 c 1 , c 2 c_1,c_2 c1,c2 使得 f ( n ) f(n) f(n) 被 c 1 ⋅ g ( n ) c_1·g(n) c1⋅g(n) 和 c 2 ⋅ g ( n ) c_2·g(n) c2⋅g(n) 夹在中间。
O O O 记号(渐进紧确上界)
对于函数 f ( n ) f(n) f(n) 和 g ( n ) g(n) g(n), f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),当且仅当 ∃ c , n 0 > 0 \exist c,n_0>0 ∃c,n0>0,使得 ∀ n ≥ n 0 , 0 ≤ f ( n ) ≤ c ⋅ g ( n ) \forall n ≥ n_0,0 ≤ f(n) ≤ c · g(n) ∀n≥n0,0≤f(n)≤c⋅g(n)。
也就是说,如果函数 f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),那么我们能找到一个正数 c c c 使得 f ( n ) f(n) f(n) 在 c ⋅ g ( n ) c·g(n) c⋅g(n) 下面。
Ω Ω Ω记号(渐进紧确下界)
对于函数 f ( n ) f(n) f(n) 和 g ( n ) g(n) g(n), f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),当且仅当 ∃ c , n 0 > 0 \exist c,n_0>0 ∃c,n0>0,使得 ∀ n ≥ n 0 , 0 ≤ c ⋅ g ( n ) ≤ f ( n ) \forall n ≥ n_0,0 ≤ c · g(n) ≤ f(n) ∀n≥n0,0≤c⋅g(n)≤f(n)。
也就是说,如果函数 f ( n ) = Θ ( g ( n ) ) f(n)=Θ(g(n)) f(n)=Θ(g(n)),那么我们能找到一个正数 c c c 使得 f ( n ) f(n) f(n) 在 c ⋅ g ( n ) c·g(n) c⋅g(n) 上面。
主定理(M定理)
主定理为用来计算递归时间复杂度的定理(Master Theorem)
假设我们用递归递推式 T ( n ) = a T ( n b ) + f ( n ) T(n) = aT(\frac{n}{b})+f(n) T(n)=aT(bn)+f(n)
其中 a a a 为递归子问题的数量, n b \frac{n}{b} bn 为每个子问题的规模, f ( n ) f(n) f(n) 为分解和合并的时间。
那么就会有三种情况:
- 当 f ( n ) f(n) f(n) 比 n l o g b a n^{log_ba} nlogba 小时, T ( n ) = Θ ( n l o g b a ) T(n) = Θ(n^{log_ba}) T(n)=Θ(nlogba)
- 当 f ( n ) f(n) f(n) 趋近于 n l o g b a n^{log_ba} nlogba 时, T ( n ) = Θ ( n l o g b a l o g n ) T(n) = Θ(n^{log_ba}logn) T(n)=Θ(nlogbalogn)
- 当 f ( n ) f(n) f(n) 比 n l o g b a n^{log_ba} nlogba 大时, T ( n ) = Θ ( f ( n ) ) T(n) = Θ(f(n)) T(n)=Θ(f(n))
二分查找的时间复杂度
T ( n ) = T ( n 2 ) + O ( 1 ) = Θ ( l o g n ) T(n) = T(\frac{n}{2}) + O(1) = Θ(logn) T(n)=T(2n)+O(1)=Θ(logn)
归并排序的时间复杂度
T ( n ) = 2 T ( n 2 ) + O ( n ) = Θ ( n l o g n ) T(n) = 2T(\frac{n}{2}) + O(n) = Θ(nlogn) T(n)=2T(2n)+O(n)=Θ(nlogn)
二叉树遍历的时间复杂度
T ( n ) = 2 T ( n 2 ) + O ( 1 ) = Θ ( n ) T(n) = 2T(\frac{n}{2}) + O(1) = Θ(n) T(n)=2T(2n)+O(1)=Θ(n)
分类
常数时间
若对于一个算法,
T
(
n
)
T(n)
T(n)与输入大小无关,则称其具有常数时间,记作
O
(
1
)
O(1)
O(1)时间。
线性时间
如果一个算法的时间复杂度为
O
(
n
)
O(n)
O(n),则称这个算法具有线性时间,或
O
(
n
)
O(n)
O(n)时间。
O ( n 2 ) O(n^2) O(n2)时间
以及
O
(
n
3
)
O(n^3)
O(n3)时间,
O
(
n
4
)
O(n^4)
O(n4)时间等
对数时间
若算法的
T
(
n
)
=
O
(
l
o
g
n
)
T(n) =O(logn)
T(n)=O(logn),则称其具有对数时间。由于计算机使用二进制的记数系统,对数常常以2为底(即l
o
g
2
n
og_2n
og2n,有时写作
l
g
n
lgn
lgn)。
推导:
设
T
(
n
)
=
l
o
g
a
n
T(n) = log_an
T(n)=logan,由换底公式可得
l
o
g
a
n
=
l
n
n
l
n
a
log_an = \frac{lnn}{lna}
logan=lnalnn,因为
l
n
a
lna
lna为常数项,省略,所以
l
o
g
a
n
log_an
logan与
l
n
n
lnn
lnn为同一数量级函数,所以底数无意义,可省略。
线性对数时间
若一个算法时间复杂度 T ( n ) = O ( n l o g n ) T(n) = O(nlog n) T(n)=O(nlogn),则称这个算法具有线性对数时间。
比较
一般来说,
O
(
n
2
)
>
O
(
n
l
o
g
n
)
>
O
(
n
)
>
O
(
l
o
g
n
)
>
O
(
1
)
O(n^2) > O(n logn) > O(n) > O(logn) > O(1)
O(n2)>O(nlogn)>O(n)>O(logn)>O(1)
关于时间复杂度
根据估计,电脑一秒钟大约能进行1亿次运算。据经验,当时间复杂度在2000w以下时,一般认为程序能在1s内跑完
空间复杂度
一个算法所耗费的存储空间记为 S ( n ) S(n) S(n);
若存在 f ( n ) f(n) f(n),使 n n n 趋近于无穷大时, S ( n ) f ( n ) \frac{S(n)}{f(n)} f(n)S(n)为不等于零的常数,则称 f ( n ) f(n) f(n)为 S ( n ) S(n) S(n)的同数量级函数,记作
S ( n ) = O ( f ( n ) ) S(n) = O(f(n)) S(n)=O(f(n))
称 O ( f ( n ) ) O(f(n)) O(f(n))为算法 S ( n ) S(n) S(n)的渐进空间复杂度,简称空间复杂度。
时空复杂度
时间复杂度和空间复杂度往往是相互影响的。当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间;反之,当追求一个较好的空间复杂度时,可能会使时间复杂度的性能变差,即可能导致占用较长的运行时间。
算法的时间复杂度和空间复杂度合称为算法的复杂度。
算法
初级算法
进阶算法
- 2.0 线性优化策略
- 2.1分治与倍增