《计算机程序设计艺术》第一卷 1.1 读书笔记
形式化定义算法(Algorithm)
\quad 算法是“一系列规则的集合”,这些规则产生求解问题所需的一系列操作。若要形式化定义算法,需先形式化定义计算方法(Computational method)。
计算方法(Computational method)的形式化定义
\quad 计算方法可以定义成四元组 ( Q , I , Ω , f ) (Q, I, \Omega, f) (Q,I,Ω,f)。其中 Q , I , Ω Q, \, I, \, \Omega Q,I,Ω 为集合, f f f 为函数,且 f : Q → Q f:Q\to Q f:Q→Q。
\quad 此外 f f f是在输出状态集合 Ω \Omega Ω 上逐点不动(Pointwise fixed)的,表示对输出状态集合中的每一个状态 q q q,都有 f ( q ) = q f(q)=q f(q)=q。
- 限定词 pointwise ,指的是“考虑函数 f f f 的每一个值 f ( x ) f(x) f(x) 的性质”。
- 这是定义,即对输出集合内的状态 q q q 应用计算规则 f f f 得到的还是它本身。这是因为把 f f f 看成一种能计算答案的机器,在 q q q 已经构成答案的情况下,在其上无论怎么重复应用规则 f f f,得到的仍然是答案 q q q。
- 这个定义非常重要,表示如果能连续应用计算规则 f f f ,从输入状态 x x x 产生输出状态 x k x_k xk,那么 x k x_k xk 是稳定的。这种情况下 f f f 对于输入状态集 x x x 是收敛的,最终会得到一个“稳定的”结果。
\quad Q Q Q 是计算过程中的所有状态集合, I I I是计算所需的输入集合, Ω \Omega Ω是计算产生的输出集合。 f f f是计算规则。 I ⊆ Q , Ω ⊆ Q I \subseteq Q,\,\Omega \subseteq Q I⊆Q,Ω⊆Q。
\quad 这里的 f f f 不可以简单理解为程序设计语言里的“函数”,例如
int f(int x) { return x + 1;}
; I I I 不可以简单理解为“函数输入”, Ω \Omega Ω 同理。
\quad 因为这里的 Q , I , Ω Q, I, \Omega Q,I,Ω 都是“状态”的集合,而 f f f是对这些状态作转换。
\quad 在输入集合 I I I 中的每一个输入 x x x 都会经过计算规则 f f f,产生一串计算序列: x 0 , x 1 , x 2 , x 3 , … x_0, x_1, x_2, x_3, \dots x0,x1,x2,x3,…,其中
x 0 = x and ∀ i ≥ 0 , x i + 1 = f ( x i ) x_0 = x\quad \text{and}\quad \forall i \ge 0, x_{i+1}=f(x_i) x0=xand∀i≥0,xi+1=f(xi)。
\quad 如果在反复运用规则 f f f 的情况下,能够在第 k k k 步找到属于输出集合的状态 x k x_k xk,那就说这个计算序列在 k k k 步停止。或者说计算规则 f f f 以状态 x x x 为输入, x k x_k xk为输出。这里的 k k k 是使得 x k ∈ Ω x_k\in \Omega xk∈Ω 的最小的正整数。
\quad (假设计算规则能停止)如果 x k ∈ Ω x_k \in \Omega xk∈Ω,那么 x k + 1 ∈ Ω x_{k+1}\in \Omega xk+1∈Ω。即, x k + 1 = f ( x k ) = x k x_{k+1}=f(x_k)=x_k xk+1=f(xk)=xk。
\quad 只有对输入集合 I I I 中的每一个输入都能停止的计算方法才能叫算法(Algorithm)。
例子:在已知自然数加减法的基础之上定义乘法 f ( ( m , n ) ) = ( m ⋅ n ) f((m, n))=(m\cdot n) f((m,n))=(m⋅n)
-
令 Q Q Q 为三元组 ( m , n , a ) (m, n, a) (m,n,a) 所构成的集合,其中 m , n , a ∈ N ∪ ∅ m, n, a\in \mathbb{N}\cup\emptyset m,n,a∈N∪∅ 。
- 把 ( m , n , ∅ ) (m, n, \emptyset) (m,n,∅) 称为初始状态,简记为 ( m , n ) (m, n) (m,n)。
- 把 ( ∅ , ∅ , a ) (\emptyset, \emptyset, a) (∅,∅,a) 称为输出状态,简记为 ( a ) (a) (a)。
-
令 I = { ( m , n ) ∣ m , n ∈ N } ⊂ Q I=\{(m, n)|\,m, n \in \mathbb{N}\} \subset Q I={(m,n)∣m,n∈N}⊂Q ,
-
令 Ω = { ( a ) ∣ a ∈ N } ⊂ Q \Omega=\{(a)|\, a\in\mathbb{N}\} \subset Q Ω={(a)∣a∈N}⊂Q。
-
而 f f f 定义为如下:
- 对初始状态作转换: f ( ( m , n ) ) = f ( ( m , n , 0 ) ) ; f((m, n))=f((m, n, 0)); f((m,n))=f((m,n,0));
- 对输出状态作转换: f ( ( a ) ) = ( a ) ; f((a))=(a); f((a))=(a);
- f ( ( m , n , a ) ) = { ( a ) , if m = 0 ( m − 1 , n , a + n ) , otherwise f((m, n, a)) = \begin{cases} (a), & \text{if } m=0 \\ (m-1, n, a+n),& \text{otherwise}\end{cases} f((m,n,a))={(a),(m−1,n,a+n),if m=0otherwise
可以使用 Python3 编写一个对上面过程的模拟程序:
class State:
def __init__(self, m, n, ans = None) -> None:
self.m = m
self.n = n
self.ans = ans
def isInitialState(self) -> bool:
return self.m is not None and \
self.n is not None and \
self.ans is None
def isFinalState(self) -> bool:
return self.m is None and \
self.n is None and \
self.ans is not None
def __str__(self) -> str:
return f"({self.ans})"
def f(state: State):
if state.isInitialState():
return f(State(state.m, state.n, 0))
elif state.isFinalState():
return state
else:
if state.m == 0:
return f(State(None, None, state.ans))
else:
return f(State(state.m-1, state.n, state.ans + state.n))
print(f(State(100, 100))) # 100 * 100
对 f f f 和 Q Q Q 的约束
\quad 为满足算法的可行性(Effectiveness),需对 f f f 和 Q Q Q 作约束。 f f f 不能是无法实现的计算规则; Q Q Q 不能包含无穷个状态,使得这种计算方法无法在物理层面实现。
…👷…