add part of chp1 notes on thu'dsa courses

This commit is contained in:
Shine wOng
2019-05-03 10:54:44 +08:00
parent d9b1b8337e
commit 93b8875a5a

101
thu_dsa/chp1.md Normal file
View File

@@ -0,0 +1,101 @@
数据结构与算法第一章知识总结
=========================
## 为什么需要数据结构和算法
讨论这个问题之前,先想想究竟什么是计算机,又什么是算法。
_Computer science should be called computing science, for the same reason why surgery is not called knife science.
-- E. Dijkstra_
## 几个实例
+ 绳索计算机以及计算垂直线的算法
+ 尺规计算机以及计算三等分点的算法。
+ 现代电子计算机以及冒泡排序的算法。
## 什么是算法
上面几个例子其实并没有本质的区别,几千年前的人们就开始研究了各种各样的算法,现代人还在重复这个研究工作。
从上面的例子中,我们可以总结出算法的基本概念:
+ 所谓计算,本质上是对信息处理的过程。对输入的数据按照机械的步骤,执行得出结果的过程。
+ 所谓计算模型,如上面的绳索和尺规,就是计算机,即信息处理的工具。
+ 这样的话,算法就是在特定的计算模型下,旨在解决问题的指令序列
- 输入
- 输出
- 正确性
- 确定性
- 可行性
- 有穷性: 如Hailstone问题尚未证实其有穷性
- ...
评价一个算法,常常具有上面这许多因素。在算法正确的基础上,我们会比较关注一个算法的代价,即它运行的时间与空间。
## 算法的评价
_Algorithm + Data Structure = Programs // N.Wirth, 1976_
_(Algorithm + Data Structure) x Efficiency = Computation // Pro Deng_
对于求解同一个问题,往往会存在许多不同的算法。问题在于,应该如何评价这些算法的优劣呢?
### 度量的基准
_To measure is to know. If you cannot measure it, you cannot improve it
-- Lord Kelvin_
考虑我们要评价两个不同算法的优劣,一个很自然的思想是实验测量,通过测量这两个算法在同一问题实例(instance)P的情况下两个算法的运行代价。即
$$T_A(P) = the cost of algorithm A to solve instance P$$
可是,这样的测量真的有意义吗?
很明显,上面的方法存在下面的问题。针对某个问题实例的测量,并不能反映算法在实际运行时的性能。因为实际运行时的问题实例有很多,不同实例之间算法的性能很难说有相关性。
那好,我们对不同的问题实例进行抽象。根据经验,一般的算法的运行代价和问题的规模是相关的。一般说来,问题的规模越大,算法运行的代价越大(当然也有反例如Hailstone)。这样我们就可以把基于问题实例P的测量转化为基于一系列规模为n的问题实例P的测量
$$ T_A(n) = the cost of algorithm to solve instances of scale n $$
有下面两种方案:
+ 最坏情况下的运行代价
+ 平均情况下的运行代价
实际上,多数情况下,我们都是关注最坏情况下算法的运行代价。
### 理想模型
有了上面的讨论后,终于可以评价算法的优劣的吧?其实还不行。因为实验测量的方法还会受到外界因素的影响。
例如绳索计算机以及尺规计算机,其运行效率与操作人员的熟练程度,当天状态是息息相关的。现代计算机也是一样,即使使用同一台机器运行两个算法,也会由于进程的调度,硬盘的读写情况不同而多少有所差异。所以,实验测量的方式是可以的,但是是不准确的。
由上面的讨论,我们需要的是理想的平台或是模型,使我们可以不再依赖于上面的各种不确定因素,从而直接准确地描述并测量算法。
+ 图灵机TM(Turning Machine)
- 有一条纸带(tape), 上面均匀地划分了小格,格子里面是字符,默认为'#'
- 字符(alphabet)的个数是有限的
- 存在一个头指针(Head),指向纸带上的某一个单元格,可以读写其中的字符
- 头指针存在状态(State), 也是TM的状态。每一步都可以改变自己的状态
- 每一步会执行一个传递函数`Transition_Function(q, c; d, L/R, p)`: 当前状态为q且当前字符为c将当前字符改写成d 当前状态改写成p并且向左L或向右R移动。一旦转入特定状态'h'(for halt),则进入停机。
- 实例:将二进制非负整数加一
+ Random Access Machine
- 具有一些顺序编号的寄存器R[0], R[1], R[2]...总数没有限制
- 具有一些基本操作,都只需要花费常数时间
```
R[i] <- c R[i] <- R[R[j]] R[i] <- R[j] + R[k]
R[i] <- R[j] R[R[i]] <- R[j] R[i] <- R[j] - R[k]
IF R[i] = 0 GOTO l IF R[i] > 0 GOTO l GOTO l STOP
```
- 实例floor向下取整的除法(就跟汇编似的)
可以看到TM模型和RAM模型一样都是把运算抽象成了各个基本操作的叠加。而这些基本操作的运行时间是固定的平台无关的。这样我们就可以独立于具体的平台对算法的效率做出可信的比较与评价。
由于每步基本操作的运行时间是固定的,因此我们可以使用算法执行所需要的基本操作的次数来评价一个算法。这样
$$T(n) = number of basic operations to solve a problem of scale n$$