1. 算法
在学习离散数学的时候如此早的便接触算法是由于在解决离散数学问题的时候需要考虑算法的相关指标。而算法就是在不断的解决离散数学问题的时候而逐渐成体系,出现了各种算法。在此处的算法只是算法的基础,但也是极其重要的。
先来看定义
定
义
1
:
算
法
是
进
行
一
项
计
算
或
解
决
一
个
问
题
的
精
确
指
令
的
有
限
序
列
。
{\color{Purple}{定义\,1:}}\,算法是进行一项计算或解决一个问题的精确指令的有限序列。
定义1:算法是进行一项计算或解决一个问题的精确指令的有限序列。
很多时候描述算法是使用伪代码的形式,需要知道伪代码中语句的意思。
算法的性质:
- 输入:算法从一个指定的集合得到输入值
- 输出:对每个输入值集合,算法都要从一个指定的集合中产生输出值。输出值就是问题的解。
- 确定性:算法的步骤必须是准确定义的
- 正确性:对每一组输入值,算法都应该产生正确的输出值。
- 有限性:对任何输入算法都应该在有限(可能很多)步之后产生期望的输出。
- 有效性:算法的每一步都应能够准确地在有限的时间完成。
- 通用性:算法过程应该可以运用于期望形式的所有问题,而不只是用于一组特定的输入值。
2. 函数的增长
在研究计算算法使用的操作步数前,需要先了解相关函数增长的知识。
定
义
1
:
令
f
和
g
为
整
数
集
或
实
数
集
到
实
数
集
的
函
数
。
如
果
存
在
常
数
C
和
k
使
得
只
要
当
x
>
k
就
有
∣
f
(
x
)
∣
≤
C
∣
g
(
x
)
∣
我
们
就
说
f
(
x
)
是
O
(
g
(
x
)
)
的
。
可
读
作
"
f
(
x
)
是
大
O
g
(
x
)
的
"
。
{\color{Purple}{定义\,1:}}\,令f和g为整数集或实数集到实数集的函数。\\ 如果存在常数C和k使得只要当x>k就有\\ |f(x)|\leq C|g(x)|\\ 我们就说f(x)是O(g(x))的。可读作"f(x)是大Og(x)的"。
定义1:令f和g为整数集或实数集到实数集的函数。如果存在常数C和k使得只要当x>k就有∣f(x)∣≤C∣g(x)∣我们就说f(x)是O(g(x))的。可读作"f(x)是大Og(x)的"。
常数
C
和
k
C和k
C和k被叫做凭证(witness)。
定
理
1
:
令
f
(
x
)
=
a
n
x
n
+
a
n
−
1
x
n
−
1
+
.
.
.
+
a
1
x
+
a
0
,
其
中
a
0
,
.
.
.
,
a
1
,
a
n
−
1
,
a
n
是
实
数
。
那
么
f
(
x
)
是
O
(
x
n
)
的
。
{\color{DarkBlue}{定理\,1:}}\,令f(x)=a_nx^n+a_{n-1}x^{n-1}+...+a_1x+a_0,其中a_0,...,a_1,a_{n-1},a_n是实数。\\ 那么f(x)是O(x^n)的。
定理1:令f(x)=anxn+an−1xn−1+...+a1x+a0,其中a0,...,a1,an−1,an是实数。那么f(x)是O(xn)的。
用于估算的常用函数包括:
1
,
l
o
g
n
,
n
,
n
l
o
g
n
,
n
2
,
2
n
,
n
!
1,logn,n,nlogn,n^2,2^n,n!
1,logn,n,nlogn,n2,2n,n!
注:
l
o
g
n
表
示
n
的
以
2
为
底
的
对
数
logn 表示n的以2为底的对数
logn表示n的以2为底的对数。
2.1 函数组合的增长
定 理 1 : 假 定 f 1 ( x ) 是 O ( g 1 ( x ) ) 的 , f 2 ( x ) 是 O ( g 2 ( x ) ) 的 , 那 么 ( f 1 + f 2 ) ( x ) 是 O ( g ( x ) ) 的 , 其 中 对 所 有 x 有 g ( x ) = ( m a x ( ∣ g 1 ( x ) ∣ , ∣ g 2 ( x ) ∣ ) ) 。 {\color{DarkBlue}{定理\,1:}}\,假定f_1(x)是O(g_1(x))的,f_2(x)是O(g_2(x))的,那么(f_1+f_2)(x)是O(g(x))的,\\ 其中对所有x有g(x)=(max(|g_1(x)|,|g_2(x)|))。 定理1:假定f1(x)是O(g1(x))的,f2(x)是O(g2(x))的,那么(f1+f2)(x)是O(g(x))的,其中对所有x有g(x)=(max(∣g1(x)∣,∣g2(x)∣))。
推 论 1 : 假 定 f 1 ( x ) 和 f 2 ( x ) 都 是 O ( g ( x ) ) 的 , 那 么 ( f 1 + f 2 ) ( x ) 也 是 O ( g ( x ) ) 的 。 {\color{DarkGreen}{推论\,1:}}\,假定f_1(x)和f_2(x)都是O(g(x))的,那么(f_1+f_2)(x)也是O(g(x))的。 推论1:假定f1(x)和f2(x)都是O(g(x))的,那么(f1+f2)(x)也是O(g(x))的。
定 理 2 : 假 定 f 1 ( x ) 是 O ( g 1 ( x ) ) 的 , f 2 是 O ( g 2 ( x ) ) 的 。 那 么 ( f 1 f 2 ) ( x ) 是 O ( g 1 ( x ) g 2 ( x ) ) 的 。 {\color{DarkBlue}{定理\,2:}}\,假定f_1(x)是O(g_1(x))的,f_2是O(g_2(x))的。\\ 那么(f_1f_2)(x)是O(g_1(x)g_2(x))的。 定理2:假定f1(x)是O(g1(x))的,f2是O(g2(x))的。那么(f1f2)(x)是O(g1(x)g2(x))的。
2.2 大 Ω \Omega Ω和大 Θ \Theta Θ
大
O
O
O是函数的上限,而大
Ω
\Omega
Ω是下下,大
Θ
\Theta
Θ是上限和下限。
定
义
2
:
令
f
和
g
为
从
整
数
集
合
或
实
数
集
合
到
实
数
集
合
的
函
数
。
如
果
存
在
正
常
数
C
和
k
使
得
当
x
>
k
时
有
∣
f
(
x
)
∣
≥
C
∣
g
(
x
)
∣
我
们
说
f
(
x
)
是
Ω
(
g
(
x
)
)
的
。
{\color{Purple}{定义\,2:}}\,令f和g为从整数集合或实数集合到实数集合的函数。\\ 如果存在正常数C和k使得当x>k时有\\ |f(x)|\geq C|g(x)|\\ 我们说f(x)是\Omega(g(x))的。
定义2:令f和g为从整数集合或实数集合到实数集合的函数。如果存在正常数C和k使得当x>k时有∣f(x)∣≥C∣g(x)∣我们说f(x)是Ω(g(x))的。
定 义 3 : 令 f 和 g 为 从 整 数 集 合 或 实 数 集 合 到 实 数 集 合 的 函 数 。 如 果 f ( x ) 是 O ( g ( x ) ) 的 且 f ( x ) 是 Ω ( g ( x ) ) 的 , 我 们 就 说 f ( x ) 是 Θ ( g ( x ) ) 的 。 我 说 f ( x 是 g ( x ) 阶 的 , 或 f ( x ) 和 g ( x ) 是 同 阶 的 。 {\color{Purple}{定义\,3:}}\,令f和g为从整数集合或实数集合到实数集合的函数。\\ 如果f(x)是O(g(x))的且f(x)是\Omega(g(x))的,我们就说f(x)是\Theta(g(x))的。\\ 我说f(x是g(x)阶的,或f(x)和g(x)是同阶的。 定义3:令f和g为从整数集合或实数集合到实数集合的函数。如果f(x)是O(g(x))的且f(x)是Ω(g(x))的,我们就说f(x)是Θ(g(x))的。我说f(x是g(x)阶的,或f(x)和g(x)是同阶的。
f ( x ) 是 Θ ( g ( x ) ) f(x)是\Theta(g(x)) f(x)是Θ(g(x))的当且仅当存在实数 C 1 C_1 C1和 C 2 C_2 C2以及应该正实数k使得当x>k时有 C 1 g ( x ) ≤ f ( x ) ≤ C 2 g ( x ) ) C_1g(x)\leq f(x)\leq C_2g(x)) C1g(x)≤f(x)≤C2g(x)) 。
一个关于多项式的更有用的事实是多项式的首项决定其阶。
定
理
1
:
令
f
(
x
)
=
a
n
x
n
+
a
n
−
1
x
n
−
1
+
.
.
.
+
a
1
x
+
a
0
,
其
中
a
0
,
a
1
,
.
.
.
,
a
n
是
实
数
,
a
n
≠
0
。
则
f
(
x
)
是
x
n
阶
的
。
{\color{DarkBlue}{定理\,1:}}\,令f(x)=a_nx^n+a_{n-1}x^{n-1}+...+a_1x+a_0,其中a_0,a_1,...,a_n是实数,a_n\neq 0。则f(x)是x^n阶的。
定理1:令f(x)=anxn+an−1xn−1+...+a1x+a0,其中a0,a1,...,an是实数,an=0。则f(x)是xn阶的。
2.3 算法复杂度
计算复杂度是在算法学习中始终需要讨论的问题。解决特定规模的问题所需时间的分析就是算法的时间复杂度。所需计算机内存的分析就是算法空间复杂度。
对于时间复杂度,在输入具有一定规模时,算法的时间复杂度可以用算法所需的运算次数来表示。
在分析时可以考虑最坏情形复杂度和平均复杂度。
关于主定理的内容,
定
理
1
:
主
定
理
设
f
是
满
足
递
推
关
系
f
(
n
)
=
a
f
(
n
/
b
)
+
c
n
d
的
增
函
数
,
其
中
n
=
b
k
,
k
是
一
个
正
整
数
,
a
≥
1
,
b
是
一
个
大
于
1
的
整
数
,
c
和
d
是
实
数
,
满
足
c
是
正
的
且
b
是
非
负
的
。
那
么
f
(
n
)
是
{
O
(
n
d
)
a
<
b
d
O
(
n
d
l
o
g
n
)
a
=
b
d
o
(
n
l
o
g
b
a
)
a
>
b
d
{\color{DarkBlue}{定理\,1:}}\,主定理\,设f是满足递推关系\\ f(n)=af(n/b)+cn^d\\ 的增函数,其中n=b^k,k是一个正整数,a\geq1,b是一个大于1的整数,c和d是实数,满足c是正的且b是非负的。那么\\ f(n)是 \left\{\begin{matrix} O(n^d)& a<b^d \\ O(n^dlog n)& a=b^d\\ o(n^{log_b^a}) & a>b^d \end{matrix}\right.
定理1:主定理设f是满足递推关系f(n)=af(n/b)+cnd的增函数,其中n=bk,k是一个正整数,a≥1,b是一个大于1的整数,c和d是实数,满足c是正的且b是非负的。那么f(n)是⎩⎨⎧O(nd)O(ndlogn)o(nlogba)a<bda=bda>bd
2.4 理解算法复杂度
复杂度 | 术语 |
---|---|
Θ ( 1 ) \Theta(1) Θ(1) | 常量复杂度 |
Θ ( l o g n ) \Theta(log n) Θ(logn) | 对数复杂度 |
Θ ( n ) \Theta(n) Θ(n) | 线性复杂度 |
Θ ( n l o g n ) \Theta(nlog n) Θ(nlogn) | 线性对数复杂度 |
Θ ( n b ) \Theta(n^b) Θ(nb) | 多项式复杂度 |
Θ ( b n ) , b > 1 \Theta(b^n),b>1 Θ(bn),b>1 | 指数复杂度 |
Θ ( n ! ) \Theta(n!) Θ(n!) | 阶乘复杂度 |
易解性( tractability ) 一个能用多项式最坏情形复杂度(或更优)的算法求解的问题称为易解的( tractable )。
但需注意即使易解性是这样定义的,但当多项式次数过高( 如 100 次)或者多项式的系数非常大,则问题也不能保证在合理的时间内得到解答。幸运的是,在实践中,多项式的次数和系数都不大。
对于那些不能用最坏情形多项式时间复杂度的算法解决的问题被称为是难解的( intractable )。
解决难解的问题可以考虑两种方法:第一种是,如果问题再大多少情况下是花费时间可以接受,只在少量情况不能在合理时间内解决,那么平均情形时间复杂度便是一种更好的度量方式。第二种是,寻求问题的近似解而非精确解。
甚至还有一些问题,被证明是没有算法能够求解它们的。这种问题被称为不可解的( unsolvable )。停机问题便是这样的一个问题。
2.4.1 P与NP
有些问题被划分到P类和NP类中。
P类问题就是易解的问题。
NP类问题是一些特殊的问题:人们相信许多可解的问题具有这样的性质,即没有多项式最坏情形时间复杂度的算法能求解,但是一旦有了一个解答,却可以用多项式时间内验证。能以多项式时间内来验证解的问题称为属于NP类。缩写NP是指非确定性多项式( nodeterministic polynomial )时间。
另外还有一类重要的问题,NP完全问题(NP-complete problem),这类问题具有这样的性质即只要其中任何一个问题能用一个多项式时间最坏情形算法来求解,那么NP类的所有问题都能用多项式时间最坏情形算法来求解。
在数学界或者说计算机界就存在这样的一个问题,P与NP问题( P versus NP problem ),是问NP是否等于P。其实就是在问NP类问题是否真的存在,如果 P ≠ N P P\neq NP P=NP,则存在这样一些不能在多项式时间内求解但其解可以在多项式时间内验证的问题。大多数理论计算机科学家相信 P ≠ N P P\neq NP P=NP,这样的看法很大部分来源于至今也没有人成功的证明 P = N P P=NP P=NP。
这个问题是7个著名的千禧年大奖问题之一,其中6个依然未解。
2.4.1 实际的考虑
需要知道的是大 Θ \Theta Θ估算是不能直接翻译成计算机实际使用时间量。第一, C 和 k C和k C和k 是不知道的。第二,运算时间还取决于运算类型和使用的计算机。
提高计算机解决问题的方法有:一,提高算法有效性;二,提高计算机存储和计算能力;三,并行处理;四,分布处理。
在我学习的该书( 离散数学及其应用 Kenneth H.Rosen 著 )中,给出了一个参考的时间。
假定一次位运算需要的时间是 1 0 − 11 10^{-11} 10−11秒。
问题规模 | ||||||
---|---|---|---|---|---|---|
n | l o g n log n logn | n n n | n l o g n nlogn nlogn | n 2 n^2 n2 | 2 n 2^n 2n | n ! n! n! |
10 10 10 | 3 × 1 0 − 11 s 3\times 10^{-11}s 3×10−11s | 1 0 − 10 s 10^{-10}s 10−10s | 3 × 1 0 − 10 s 3\times10^{-10}s 3×10−10s | 1 0 − 9 s 10^{-9}s 10−9s | 1 0 − 8 s 10^{-8}s 10−8s | 3 × 1 0 − 7 s 3\times 10^{-7}s 3×10−7s |
1 0 2 10^2 102 | 7 × 1 0 − 11 s 7\times 10^{-11}s 7×10−11s | 1 0 − 9 s 10^{-9}s 10−9s | 7 × 1 0 − 9 s 7\times10^{-9}s 7×10−9s | 1 0 − 7 s 10^{-7}s 10−7s | 4 × 1 0 11 y r 4\times10^{11}yr 4×1011yr | * |
1 0 3 10^3 103 | 1.0 × 1 0 − 10 s 1.0\times 10^{-10}s 1.0×10−10s | 1 0 − 8 s 10^{-8}s 10−8s | 1 × 1 0 − 7 s 1\times10^{-7}s 1×10−7s | 1 0 − 5 s 10^{-5}s 10−5s | * | * |
1 0 4 10^4 104 | 1.3 × 1 0 − 10 s 1.3\times 10^{-10}s 1.3×10−10s | 1 0 − 7 s 10^{-7}s 10−7s | 1 × 1 0 − 6 s 1\times10^{-6}s 1×10−6s | 1 0 − 3 s 10^{-3}s 10−3s | * | * |
1 0 5 10^5 105 | 1.7 × 1 0 − 10 s 1.7 \times 10^{-10}s 1.7×10−10s | 1 0 − 6 s 10^{-6}s 10−6s | 2 × 1 0 − 5 s 2\times10^{-5}s 2×10−5s | 0.1 s 0.1s 0.1s | * | * |
1 0 6 10^6 106 | 2 × 1 0 − 10 s 2\times10^{-10}s 2×10−10s | 1 0 − 5 s 10^{-5}s 10−5s | 2 × 1 0 − 4 s 2\times10^{-4}s 2×10−4s | 0.17 m i n 0.17min 0.17min | * | * |