算法设计与分析课程复习笔记1——算法基础(含插入、合并排序)
算法概述
算法的定义
非正式地说,算法是任何良定义的计算过程,该过程取某个值或值的集合作为输入并产生某个值或值的集合作为输出。
算法是对一个过程的一步一步的描述,如果严格遵循它,就会产生一个良定义的结果。
算法是为了求解问题而给出的指令序列。(程序只是算法的一种实现。)
算法的表述
- 自然语言(English……)
- 算法描述语言(Pseudo-code)
- 计算机程序语言(C++,Java……)
- 硬件设计(DSP)
算法的一般特性
- 正确性:对于符合输入类型的任意输入数据,都产生正确的输出。
- 有效性:每一步指令能够被有效的执行,并且规定了指令的执行效果,结果应该具有的数据类型,而且是可以预期的。
- 确定性:每一步之后都要有确定的下一步指令。
- 有穷性:有限步内结束。
算法效率
有限资源:计算时间,存储空间,网络带宽
效率分析是为了有效地利用资源。
资源开销与输入大小有关,与输入的组织结构有关(有序、无序)。
时空资源折中原理
对于同一个求解问题,一般会存在多种算法,这些算法在时空开销上的优劣往往表现出“时空折中”的性质,即为了改善一个算法的时间开销,往往可以通过增大空间开销为代价,设计出一个新算法来。
算法渐进分析
随着问题规模变大算法的变现如何?考虑运行时间,存储需求。
在分析时,我们采用RAM模式:
- 存储空间访问开销均等
- 顺序无并发
- 指令执行周期相同,除了程序调用之外
- 字节长度一致
渐进分析的目的是得到一个开销函数的渐进表达式,比如大O渐进表达式。
确定情况 矩阵加法
问题规模:n=k2
T(n)=
c
1
c_1
c1(k+1)+
c
2
c_2
c2k(k+1)+
c
3
c_3
c3kk=ak2+bk+c=an+bn1/2+c
r
a
t
e
T
(
n
)
rateT(n)
rateT(n)
=
O
(
f
(
n
)
)
=O(f(n))
=O(f(n))
n
→
\rightarrow
→
∞
\infty
∞
f(n)=n
条件情况 插入排序
算法如下:
InsertionSort(A, n) { cost reptitions
for i = 2 to n { c1 n
key = A[i] c2 n-1
j = i - 1 c3 n-1
while (j > 0) and (A[j] > key) { c4 t2+……+tn
A[j+1] = A[j] c5 (t2-1)+……+(tn-1)
j = j - 1 c6 (t2-1)+……+(tn-1)
}
A[j+1] = key c7 n-1
}
}
example:
- 30 10 40 20
↓ - 30 30 40 20
↓ - 10 30 40 20
↓ - 10 30 40 40
↓ - 10 30 30 40
↓ - 10 20 30 40
最好情况: 输入为10,20,30,40
t
i
t_i
ti=1
T(n)=(
c
1
c_1
c1+
c
2
c_2
c2+
c
3
c_3
c3+
c
4
c_4
c4+
c
7
c_7
c7)n-(
c
2
c_2
c2+
c
3
c_3
c3+
c
4
c_4
c4+
c
7
c_7
c7)=an+b
最坏情况: 输入为40,30,20,10
t
i
t_i
ti=i
T(n)=an2+bn+c
最坏、最好和平均情况
渐进分析与阶的增长
- 开销函数的估计是相对的而不是绝对的
- 独立于机器的算法开销估计
- 独立于实现技术的算法自身测度表示
- 关心的是大规模输入的情况
忽略了开销函数的低阶项和常数项,度量的是算法渐进的开销,此时,开销函数的阶的增长决定了开销的大小。
符号表示
- f(n) = O(g(n)) if ∃c > 0, n 0 n_0 n0 > 0 s.t. ∀n ≥ n 0 n_0 n0: f(n) ≤ c ⋅ g(n)
- f(n) = Ω(g(n)) if ∃c > 0, n 0 n_0 n0 > 0 s.t. ∀n ≥ n 0 n_0 n0: f(n) ≥ c ⋅ g(n)
- f(n) = Θ(g(n)) if ∃ c 1 c_1 c1, c 2 c_2 c2 > 0, n 0 n_0 n0 > 0 s.t.∀n ≥ n 0 n_0 n0: c 1 c_1 c1 · g(n) ≤ f(n) ≤ c 2 c_2 c2 ⋅ g(n)
- f(n) = ω(g(n)) if ∀c > 0 ∃ n 0 n_0 n0 > 0 s.t. ∀n ≥ n 0 n_0 n0: f(n) ≥ c ⋅ g(n)
- f(n) = o(g(n)) if ∀c > 0 ∃ n 0 n_0 n0> 0 s.t. ∀n ≥ n 0 n_0 n0: f(n) ≤ c ⋅ g(n)
公式
- f(n) = O(f(n)) f(n) = Ω(f(n)) f(n) = Θ(f(n))
- f(n) = O(g(n)) and g(n) = O(h(n)) ⇒ f(n) = O(h(n))
- f(n) = Ω(g(n)) and g(n) = Ω(h(n)) ⇒ f(n) = Ω(h(n))
- f(n) = Θ(g(n)) and g(n) = Θ(h(n)) ⇒ f(n) = Θ(h(n))
- f(n) = O(g(n)) ⇐⇒ g(n) = Ω(f(n))
- f(n) = o(g(n)) ⇐⇒ g(n) = ω(f(n))
- f(n) = O(g(n)) and f(n) = Ω(g(n)) ⇒ f(n) = Θ(g(n))
- f 1 f_1 f1(n) = O( g 1 g_1 g1(n)) and f 2 f_2 f2(n) = O( g 2 g_2 g2(n)) ⇒ f 1 f_1 f1(n) + f 2 f_2 f2(n) = O( g 1 g_1 g1(n) + g 2 g_2 g2(n))
- f(n) = O(g(n)) ⇒ f(n) + g(n) = O(g(n))
常见的规模的整函数表达式的f(n)
f(n)=1, 常数函数,不依赖于n
f(n)=log n, 对数函数,比线性函数增长慢
f(n)=n
f(n)=n2
f(n)=nlog(n)
f(n)=an, 指数增长
算法效率比较
如果满足以下公式
T
A
T_A
TA(n) = o(
T
B
T_B
TB(n))
则算法A好于算法B
合并排序
1个元素的情况:已经排好,完成。
其他情况:二等分,两部分递归排序,整合排序好的两部分,完成。
算法如下:
MergeSort(A,p,r) T(n)=
if p<r
then
q←
⌊
\lfloor
⌊(p+r)/2
⌋
\rfloor
⌋ c1+
MergeSort(A,p,q) T(n/2)+
MergeSort(A,q+1,r) T(n/2)+
Merge(A,p,q,r) c2*n
小结:
两种排序算法:
插入排序 takes c1*n2 time
合并排序 takes c2*nlogn time
合并排序优于插入排序。
参考:任课教师邱德红教授的课件