MIT 6.00 导论课程笔记(三)
2017-02-14 20:29
316 查看
Lecture 09
二分法
实际上是重复了 Lecture 8 的内容。Lisp语言存储列表是使用了box pointer diagram,使用的是链表,每一个盒子有两个指针,一个指向下一个位置,一个指向值对象。这种存储链表的方式如果要找到第i个列表元素的话,需要按顺序一个一个的来,即线性查找时间。
Python和Fortran语言改进了这一问题,采用了另一种方式来存储列表。使用一整块来存储数据,每一块中每一个格子都有一个指针,指针指向值对象。
这两种的区别在于Python的方法省去了指向下一个指针,直接分配一整块内存给链表。这两种方法各有优劣,都是对访问时间和空间权衡之后得出的决策。
二分法隐藏的通用思想
Pick the mid point
Check to see if this is answer
If not, reduce to small problem repeat
我们应该在search之前sort吗?
搜索无序表时,复杂度为n。搜索有序表时,复杂度最快为nlogn。
然而,如果我们要搜索 k 次呢?
搜索无序表时,复杂度为kn
4000
搜索有序表时,复杂度为nlogn+klogn
代码
#冒泡排序 def bubbleSort1(L): for j in range(len(L)): for i in range(len(L)-1): if L[i] > L[i+1]: temp = L[i] L[i] = L[i+1] L[i+1] = temp print L print '*******' def bubbleSort(L): swapped = True while swapped: swapped = False for i in range(len(L)-1): if L[i]>L[i+1]: temp = L[i] L[i] = L[i+1] L[i+1] = temp swapped = True print L print '********' #选择排序 def selectionSort(L): for i in range(len(L)): minIndex = i minVal = L[i] for j in range(i,len(L)): if L[j] < minVal: minIndex = j minVal = L[j] L[minIndex] = L[i] L[i] = minVal print L
Lecture 10
分治法
分治算法概要步骤将问题分割为同类型的子问题
单独解决这些子问题
联合这些解决办法
归并排序
归并排序是分治法的一个重要例子将列表分割成一半
继续分割直到每个列表都有一个元素
归并这些子列表
def merge(left, right): result = [] i,j = 0,0 while i < len(left) and j < len(right): if left[i] <= right[j]: result.append(left[i]) i = i+1 else: result.append(right[j]) j = j + 1 while i < len(left): result.append(left[i]) i = i + 1 while j < len(right): result.append(right[j]) j = j+1 return result def mergeSort(L): if len(L)<2: return L[:] else: middle = len(L)/2 left = mergeSort(L[:middle]) right = mergeSort(L[middle:]) together = merge(left,right) print 'merged',together return together
哈希
哈希算法的意思是给列表中的每个元素一个对应的索引值。给时间以空间
要创建一个完全平均的哈希算法是困难的(完全平均的意思是列表中每个元素被检索到的时间都是一样的)
代码示例
#这是一个整数对应整数索引的哈希算法,哈希表为small-large def create(smallest,largest): intSet = [] for i in range(smallest,largest+1): intSet.append(None) return intSet def insert(intSet,e): intSet[e] = 1 def member(intSet,e): return intSet[e] == 1 #这是一个字母对应整数的哈希算法,利用计算机内部的ascii创建 def hashChar(e): return ord(e) def cSetCreate(): cSet = [] for i in range(0,255): cSet.append(None) return cSet def cSetInsert(cSet,e): cSet[hashChar(e)] = 1 def cSetMember(cSet,e): return cSet[hashChar(e)] == 1
Exception异常
这是python另一个语法机制。可以分为
Unhandled exception
Handled exception
代码示例
#try...except被叫做tri-accept block def readFloat(requestMsg,errMsg): '''test exception''' while True: val = raw_input(requestMsg) try: val = float(val) return val except: print errMsg
区分异常(Exception)和断言(Assert)
我的理解是:
断言是为了防止用户输出一些不符要求的值而强行检查退出;
异常则是主要防止程序真正运行时一些乱七八糟的错误。
Lecture 11
这节课几乎是纯理论的东西,讲述的是测试和调试。验证(Validation):是隐藏问题和增加自信心的过程,是测试(testing)和寻因(reasoning)的集合。
调试:定位并解决程序失败的问题。
防卫性程式设计
Testing
测试:主要是考察输入/输出的表现主要分为单元测试和集成测试
测试集的选取要合理,要大到可以给予我们信心,也要小到时间合理。
bug
关于bug有两条西式的谬论bugs crawl in programs
bugs breed
John认为有两条非常好的调试工具,一个是print语句,另一个是代码阅读。
关于调试,还有一个重要思想:系统化的思想。
如何系统化?
研究程序文本
研究如何挽回
寻找生成此项错误的最简输入
二分法查找可能出错的地方
代码示例:
def silly(): res=[] done=False while not done: elem = raw_input('Enter element, return when done') if elem == '': done = True else: res.append(elem) #二分法第一步:选择中间部分输出查看,发现前面没问题 #print 'res ',res #定位问题,‘=’将前后引用指向了统一个对象 tmp = res #如下代码进行解决 #tmp = res[:] tmp.reverse() print 'res ',res,' tmp ',tmp #第二步,在后面的中间进行print,发现问题 #查到bug所在,bug的原因是tmp和res指向同一个对象 isPal = (res == tmp) if isPal: print 'is palindrome' else: print 'not palindrome'
Lecture 12
关于调试
编程者经常犯的小错误有:自变量的顺序错误
拼写错误
初始化错误
Object vs Values
假名错误
副作用
我们需要建立一个自己的犯错模型。
John对于编程者的建议有:
记录下你所有的曾经的尝试,不要重复犯错
重新考虑代码思路
调试代码而非注释
寻求他人帮助
休息一会再来看
慢一点,欲速不达
控制代码的行数
保存旧的版本
优化问题
简而言之就是两个部分:一个需要求极值的函数
函数上的约束
经典的优化问题有:最短路径问题,旅行商问题,序列对齐问题等。接下来要介绍的是背包问题。
连续背包问题
假设一个小偷,他只有一个8磅的背包,有三种货物,4磅的金砂,3磅的银砂和10磅的葡萄干。如果这个小偷想拿到最有价值的分配,他该怎么做?显而易见的做法是:
先装4磅金砂,再装3磅银砂,最后装1磅的葡萄干。
为什么说这个问题是连续背包呢?因为金砂还有银砂可以看做是无限小的。
这个问题的数学描述是
function=cg×pg+cs×ps+cr×pr
constraints=pg+ps+pr≤8
其中cg,cs,cr分别代表金砂的价值,银砂的价值和葡萄干的价值;
pg,ps,pr分别代表金砂的重量,银砂的重量和葡萄干的重量。
这个问题使用贪婪算法就可以解决。
但是,
局部最优并不能总是保证全局最优。
不连续背包问题
0/1 Knapsack Problem不连续背包问题中物品的重量是不能再细分的。
同样是一个小偷,他有8磅容量的背包,房间内物品有
表,重0.5磅,价值A位,两块
收音机,重2磅,价值D位,两块
Tiffany花瓶,重5磅,价值B位,两个
Velvet Evis,重6磅,价值C位,两块
现在有三个小偷
一个是贪婪的贼,使用贪婪算法(greedy algorithm),他的选择是先拿最贵的,也就是表∗2+花瓶∗1
一个精心思考的慢性子的贼,他会使用蛮力法(Bruce algorithm),他的选择时把每种选择都试一遍,他最后还没试出最优解就被抓到警察局了。
还有最后一种使我们这样聪明的贼。
现在用数学公式描述一下上述问题
function=∑i=1nPiXi
constraint=∑i=1nwiXi
其中,n是物品的总数,wi是第i个物品的重量,Pi是第i个物品的价值,X是一个向量,例如(0,0,0,0,0,0,0,0)代表8个物品中没有取任意一个。
动态编程
Dynamin Programming, John说这个名字没有任何意义。它的重点在于
overlapping subproblems(重叠子问题)
optimal substructrure(优化子结构)
相关文章推荐
- MIT 6.00 导论课程笔记(一)
- MIT 6.00 导论课程笔记(二)
- MIT 6.00 导论课程笔记(四)
- MIT开发课程-计算机科学及编程导论-课程简介及数据类型-笔记
- MIT开发课程-计算机科学及编程导论-列表和可变性、字典、效率简介-笔记
- MIT6.00 1x Lecture 1 - Introduction to Computation 学习笔记
- MIT领导力课程笔记3:前Nokia 总裁Ollila——打造移动未来
- 【MIT领导力课程笔记】现任CISIO CTO(前Motorola CTO)Padmasree Warrior——创新转化产品的无缝转换
- 【MIT领导力课程笔记】前Nokia 总裁Ollila——打造移动未来
- MIT计算机科学及编程导论02课学习笔记
- MIT线性代数课程笔记对应代码-【lecture 3】
- MIT线性代数课程笔记对应代码-【lecture 4】
- MIT 线性代数课程 笔记
- MIT领导力课程笔记:施乐前CEO Anne——在火线上得到的经验
- MIT 6.00 1x Lecture 6 Objects 对象 学习笔记
- Writing in the Sciences 课程笔记 (导论、句子和段落)
- MIT 6.046J / 18.410J 2001秋季课程:算法导论(Introduction to Algorithms, Fall 2001)第一课
- 耶鲁大学开放课程:心理学导论:这就是你的大脑 笔记_2
- MIT公开课:计算机科学及编程导论 Python 笔记4 函数分解抽象与递归
- MIT领导力课程笔记4:现任CISIO CTO(前Motorola CTO)Padmasree Warrior——创新转化产品的无缝转换