您的位置:首页 > 其它

算法导论 学习笔记 第二章 算法入门

2017-07-26 19:39 232 查看

首先附上一个算法导论学习指南链接CRLS 学习指南。这是我学习最重要的参考文章

第二章 算法入门

这一章主要讲了三个部分,第一部分是通过插入排序引出了伪代码/循环不变式两个概念。
第二部分分析算法,首先提出RAM模型,然后通过分析插入算法分析解释了复杂度,最坏/最好的情况,还稍微提了一下算法运行时间的增长率。


插入排序

对于插入排序的解释真可谓是通俗易懂啊。我以前一直是懵懵懂懂插入排序的含义,就算是可以实现但是比较费劲。
没有一个系统的框架。但是看了算法导论中的扑克牌举例,那真实教醍醐灌顶。
就像从桌子上逐个拿一些没有排序的牌,然后每拿一个牌就将其插入到制定的位置。直到所有的牌都拿到手里的时候牌也已经排好了。

这里最重要的内容是引出了*循环不变式*并且讲述了如何用循环不变式来判断算法的正确与否。


循环不变式

循环不变式有三个属性:初始化,保持,终止。
1.初始化:这个就是算法一开始循环不变式式正确的
2.保持:如果某一次迭代开始之前循环不变式式正确的。那么下一次迭代开始的时候依然是正确的。
3.循环终止的时候循环不变时将会告诉我们算法式正确的。


那如何在插入排序算法中使用循环不变式来判断算法的正确呢?

1.初始化(initialization):算法第一循环的时候,我们假设数组第一个元素是已经排好序的。(废话,就一个元素)

2.保持(maintenance):如果某一个循环,例如第j次循环开始之前循环不变式:就是数组的前j-1个元素是已经排好的。
那等到第j+1次循环开始之前,也就是将第j个元素插入到准确的位置后,数组的前j个元素依然是排好的。

3.循环运行到最后一次然后for语句的判断语句为假的时候j = n + 1了。
这个时候循环不变式:也就是数组的前n个元素已经排好了。前n个元素也就是整个数组已经排好了。
这证明插入排序算法是正确的。

在第一部分还讲了9条关于伪代码规则:
1.用缩进表示块结构
2.循环,判断语句跟程序语言好是一样的
3.三角形表示主食
4.可以进行多重赋值,例如:j➡️(倒过来)i➡️(倒过来)➡️ 7 。表示i = j = 7;
5.如果没有特殊制定,变量都是本地变量
6.数组是用下标来访问。还有用两个..表示从..到。
7.组合的数据有属性和域
8.意思是伪代码用传值调用吧
9.and和or是有短路这个概念的。


算法分析

RAM模型

算法的分析是预测算法需要的资源。书中讲,虽然这个资源偶尔指的是内存,通讯宽带,计算机硬件这些东西。但是最主要的资源指的是运行时间。
一般来讲一个问题有多种解决方法。我们找出其中最有效率的还是比较简单的。用这种方法也许能找出几个有效的算法。但是有些算法还是要扔的。

在分析算法之前要建立一个分析算法的资源和花费的模型。书中用的就是RAM(radom - access machine)模型。
值得注意的是RAM模型是运行完一个指令在运行下一个。没有并行运行。

书中讲,应该严格的定义RAM模型,但是这样的话非常枯燥并且对于分析算法来讲没什么影响。
虽然没有严格的定义RAM模型,但是书中提了一句:不能滥用RAM模型。
RAM模型包含了一些基本的真实的计算机运行的指令:包括算数/移动数据/控制(不懂)而假设这些运算的花费的时间是常数。
还有RAM模型中数据类型有整形和浮点型两种。

最后一部分表示分析算法是比较难的。就算是分析一个非常简单的算法也是比较有挑战性的。
而且要用到一些数学知识:组合学,概率论,代数(好像这才是难点)。


分析插入排序算法

书中讲,很多时候运行时间的函数是以输入的规模来作为参数的。而每一种情况当中的输入规模的定义都不一定相同。
所以首先要定义输入规模(input size)和运行时间(running time)。
关于输入规模书中用排序算法的输入/两个整数相乘等例子说明。

插入排序的分析,是在伪代码的基础上,假设每一个指令运行的时间是常数时间,
然后与运行次数相乘然后所有的指令花费的时间加起来就是算法的运行时间。

结果是运行时间分了两种情况:
1.最好的情况是数组是已经排好序的。这个时候运行时间(n是数组大小):an+b。是关于n的线性函数。
2.最坏的情况是数组是逆排序的。这个时候运行时间是an^2+bn+c。是关于n的平方级函数。


最坏的情况和平均情况的分析

书中提出了最坏和平均两种情况。但是表示最坏的情况才是我们主要需要关注的。原因如下:
1.最坏情况的运行时间是算法运行时间的一个上线。没有比这更坏的了。这是一种保证。还有就是也不需要在多做复杂的假设来考虑更坏的情况。
2.对于某些算法来讲最坏的情况是经常发生的。比如搜索算法。如果要搜索的东西不在数据库里。而这个是经常发生的。
3.平均情况很多时候其实跟最坏情况一样差。书中用插入排序了来举例。平均情况的运行时间也是n的平方级的。


增长率

这里只是简答的讲了一下,主要意思是增长率高的比如是立方级的也许在输入规模很小时的时候效率比平方级的算法高,
但是当数据规模很大时肯定是平方级的效率高了。增长率是第三章的主要内容。


算法设计

这一部分的主要内容是将了分治法。分治法是一种讲比较大的问题递归的分解成若干个非常小,
小到可以直接解决的相似的问题,然后讲结果合并成为大问题的结果。
分治法以一下三个步骤形成
1.分解(divide):将问题分解成若干个子问题
2.解决(conquer):将子问题解决掉
3.组合(combine):将子问题的结果组合成为大问题的结果。


分治法的应用:归并排序(merge sort)

1.分解:将待排序的数组分成两个数组
2.解决:继续递归分解问题,直到每一个数组只有一个元素(不用动手已经排好了)
3.将数组合并形成排序好的数组


使用循环不变式判断归并排序的正确性

备注:这一部分我其实没怎么明白。欢迎大家来指正,谢谢

1.初始化:循环开始的时候待排序的数组其实是空的(空的也算排好的喽)。就是分成两个子数组的最小元素都还在各自子数组当中。

2.保持:在一个循环开始之前循环不变式是正确的。表示复制到待排序数组中的元素是排好的。
并且这次循环不管是从哪一个子数组当中的最小元素是小的然后复制到待排序数组当中。待排序数组还是排好的。
并且拿了一个元素的子数组的下标+1。

3.终止:循环终止的时候在子数组中只留下最大的哨兵元素。所有元素都已经在待排序数组中已经完成排序。


分析分治法算法

这里用分析归并排序算法用来举例。用的方法是递归树方法。递归树方法是将递归方程是以竖着的方式展开。
然后相加每一层中每一个节点用的时间。再将各层使用的时间相加得到算法的运行时间。

书上讲的够详细。我也讲不好。递归树是解决分治法算法的运行时间的好方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: