开篇语
今天开始看《算法导论》的第二章--算法基础,主要内容是讲述了循环不变式以及排序算法的设计以及复杂度的计算,文中巧妙地运用了扑克牌的插牌来形象的表达了排序算法的内在内容,十分的生动形象。
正文
一、插入算法
循环不变式三性质:
- 初始化(循环第一次迭代之前)的时候,它为真;
- 如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真;
- 循环结束的时候,不变式为我们提供一个有用的性质,该性质有助于证明算法是正确的。
伪代码的一些规定:
排序中的插入算法:
INSERTION-SORT(A) #A是一个等待排序的数组
1 for j=2 to A.length
2 key=A[j]
3 //Insert A[j] into the sorted qequence A[1..j-1] #把数组中的第j个数字取出来
4 i=j-1
5 while i>0 and A[i]>key //取出已经排好的前面的,如果满足取出的数大于小于之排好的数,那么进入循环
6 A[i+1]=A[i]
7 i=i-1 //将大的数放到高序号,然后再次对更加之前的数进行比较。
8 A[i+1]=key
插入算法如果类比到插牌的过程中,那么就是类似一把牌,按照从左到右大小的顺序排好,那么每抽上来一只牌,都与目前最右边的进行比较, 如果比它大,那么就放在最右边;如果比它小,那么就与右边数过来第二张进行比较。直到找到比它小的那张牌,就插在那张牌的右边。
算法的复杂度分析
定义:如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数 T(n)称为这一算法的“时间复杂性”。
当输入量n逐渐加大时,时间复杂性的极限情形称为算法的“渐近时间复杂性”。
我们常用大O表示法表示时间复杂性,注意它是某一个算法的时间复杂性。大O表示只是说有上界,由定义如果f(n)=O(n),那显然成立f(n)=O(n^2),它给你一个上界,但并不是上确界,但人们在表示的时候一般都习惯表示前者。
此外,一个问题本身也有它的复杂性,如果某个算法的复杂性到达了这个问题复杂性的下界,那就称这样的算法是最佳算法。
“大O记法”:在这种描述中使用的基本参数是 n,即问题实例的规模,把复杂性或运行时间表达为n的函数。这里的“O”表示量级 (order),比如说“二分检索是** O(logn)**的”,也就是说它需要“通过logn量级的步骤去检索一个规模为n的数组”记法 O ( f(n) )表示当 n增大时,运行时间至多将以正比于 f(n)的速度增长。
这种渐进估计对算法的理论分析和大致比较是非常有价值的,但在实践中细节也可能造成差异。例如,一个低附加代价的O(n^2)算法在n较小的情况下可能比一个高附加代价的 O(nlogn)*算法运行得更快。当然,随着n足够大以后,具有较慢上升函数的算法必然工作得更快。
对给定规模的输入,一个算法的运行时间可能结果如下图,对我们本次讲解的插入算法,最佳情况是:T(n)=an+b;最差的结果是:T(n)=an^2+bn+c
二、分治法
分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
分治法分解之后合并所需要的算法的伪代码
MERGE(A,p,q,r)
1 n1=q-p+1
2 n2=r-q
3 let L[1..n1+1] and R[1..n2+1] be new arrays
4 for i=1 to n1
5 L[i]=A[p+i-1]
6 for j=1 to n2
7 R[j]=A[q+j]
8 L[n1+1]=&
9 R[n2+1]=&
10 i=1
11 j=1
12 for k=p to r
13 if L[i]<=R[j]
14 A[k]=L[i]
15 i=i+1
16 else A[k]=R[j]
17 j=j+1
分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。
如果原问题可分割成k个子问题,1<k≤n,且这些子问题都可解并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。
定义整个分支法的伪代码。进行递归调用,知道最终每一个子序列都排列好,然后进行MERGE合并。就好比是把一堆牌,分摊成等分的两堆,然后分成四堆,一直到最后,每一堆只剩下一张牌,不能再分。这时候就可以进行合并,采用的伪代码如上所述。
结束语
不得不说这个东西还真是厉害,也不愧是我学长说一个寒假也就看完一两章的神书。这第一章具体的算法,就让我花了整整半天时间去琢磨,现在脑子还是有点晕乎乎的。加油 继续继续~~~
个人宣言
知识传递力量,技术无国界,文化改变生活!