算法导论2-2
读书笔记
分析算法帮助我们选出某个问题的更优算法;
我们应该使用一个统一的标准去衡量算法的优劣,此处使用——RAM(random-access machine),一个通用的单处理器计算模型。
RAM模型对各种指令的执行时间定义为常量,注意,对于不同的指令该常量值不同;
对于插入排序,数据规模
n
和执行时间T
,有着如下关系:
如果数组已经是排好序的,那么这是该算法的最好情况;此时,数据规模n
和执行时间T
,关系如下:
这是一个一元一次方程;
如果数组完全是乱序的,那么这是该算法的最坏情况;此时,数据规模n
和执行时间T
,关系如下:
这是一个一元二次方程;
一般来说,我们只考虑最坏的情况,为什么呢?
- 最坏情况让我们有个底
- 对于某些算法,最坏情况经常出现;
- 事实上,普通情况下的排序情况并没有比最坏情况好太多;
但是对我们来说,上述函数仍然有些复杂,对于较大的
n
,我们只需要关注增长级数高的一项,此处对应的是 \(\frac{c_5+c_5+c_7}{2}n^2\) ,然而面对大的输入,确定计算效率时,常量的影响不如\(n^2\),此时我们忽略这些常量;运行时间以\(\theta(n^2)\)记录;
课后习题
2.2-1
使用\(\theta\)记号表示函数\(\frac{n^3}{1000}-100n^2-100n+3\)
答案为:\(\theta(n^3)\)
2.2-2
考虑排序存储在数组A中的n个数:首先找出A中的最小元素并将其与A[1]中的元素进行交换。接着,找出A中的次最小元素将其与A[2]中的元素进行交换。对A中的前\(n-1\)个元素按该方式继续。该算法成为选择算法,写出其伪代码。该算法的循环不变式是什么?为什么它只需要对前\(n-1\)个元素进行操作,而不是对所有的n个元素操作?用\(\theta\)记号给出最好情况和最坏情况的运行时间。
for i = 1 to A.length -1{
for j = A.length to A.length -i{
if (A[j] > A[j-1]){
result = j-1
}
}
tmp = A[result]
A[result] = A[i]
A[i] = tmp
}
因为每次都从未排序的数组中选出最小的,当选了\(n-1\)个之后,就只剩下一个最大数;
\(\theta(n^2)\)
2.2-3
再次考虑线性查找问题,假定要查找的元素等可能的为数组中的任意元素,平均需要检查输入序列的多少元素?最坏的情况又如何?使用\(\theta\)记号给出线性查找的平均情况和最坏情况的运行时间?证明你的答案。
平均检查\(\frac{n+1}{2}\)个元素;
最坏检查\(n\)个元素;
时间复杂度为\(\theta(n)\)
2.2-4
对于任何一个算法,我们应该如何修改才能使之拥有最好的运行时间?
一种算法能够在一种情况下拥有最好的运行时间,并不意味着在其他更加普通的情况下拥有同样的表现。