python交互式程序设计导论答案第五周_MIT6.00.1X 计算机科学和PYTHON编程导论 第五周...

第九讲 效率和增长量级

我们的首要目标就是让代码正常运行,能够计算出正确的答案。尽管如此,我们还是希望代码能够达到第二个目标,即高效地进行计算。通常而言,第一个目标更加重要,但有时候第二个目标也十分重要,同时我们需要平衡计算的复杂度和理解代码的复杂度。

复杂度 :

我们假设一个基本步骤就是一个操作,而这个操作的用时总是一样的,之后我们只需专注于数清楚计算函数时所执行的基本步骤即可。测量复杂度我们只关心增幅最快的项,并且忽略系数。

例:

def f(x):

for i in range(1000):

ans = i

for i in range(x):

ans += 1

for i in range(x):

for j in range(x):

ans += 1

#这一段代码的步骤总数为1000+2x+2x^2,对于其复杂度我们只关心增长最快的项即2x^2,

#同时我们不关心系数就得到该函数的复杂度x^2。对于复杂度我们使用大写的O表示,

#则该函数的复杂度表示为O(n^2)

常见的复杂度(耗时,由低到高):

O(1) 常数时间算法,运算时间不随运算量的增加而增加

O(log n) 对数时间算法

O(n) 线性时间算法

O(n * log n) 对数-线性时间算法

O(n^c) 多项式时间算法

O(c^n) 指数时间算法

# 对数时间算法

def intToStr(i):

digits = '0123456789'

if i == 0:

return '0'

result = ''

while i > 0:

result = digits[i%10] + result

i = i/10

return result

# 运算步骤 log10(i) 复杂度 O(log(i))

# 线性时间算法

def addDigits(s):

val = 0

for c in s:

val += int(c)

return val

#总步骤 len(s) 复杂度O(len(s))

def fact(n):

if n == 1:

return 1

else:

return n*fact(n-1)

#总步骤 n 复杂度O(n)

# 多项式时间算法

def isSubset(L1, L2):

for e1 in L1:?

matched = False

for e2 in L2:

if e1 == e2:

matched = True

break

if not matched:

return False

return True

# 总步骤为 len(L1)*len(L2) 这里我们只考虑最坏的情况即 len(L1) == len(L2)

# 所以这个算法的复杂度为 O(len(L1)^2)

def intersect(L1, L2):

tmp = []

for e1 in L1:

for e2 in L2:

if e1 == e2:

tmp.append(e1)

res = []

for e in tmp:

if not(e in res):

res.append(e)

return res

# 总步骤为 len(L1)*len(L2) + len(L1) 我们只关心增长最快的项,

# 所以这个算法的复杂度为O(len(L1)^2)

# 指数时间算法

def genSubsets(L):

res = []

if len(L) == 0:

return [[]] #list of empty list

smaller = genSubsets(L[:-1])

# get all subsets without last element

extra = L[-1:]

# create a list of just last element

new = []

for small in smaller:

new.append(small+extra)

# for all smaller solutions, add one with last element

return smaller+new

# combine those with last element and those without

# 总步骤为 2^(n-1)+..+...+2^0, 所以该算法的复杂度为O(2^n)

第十讲 内存和查找

我们可以同过间接索引的办法来查找需要的数据。

一般的对于无序列表的查找,时间复杂度为O(n),而有序列表可通过二分查找将时间复杂度缩短为O(log(n)),所以我们可以通过对列表排序,使其变成有序的,再使用二分查找,只要我们找到一种排序算法使得 sort(L) + log(len(L)) < len(L) 则运算效率将会更高,而且对于多次查找,效率的提升就更加明显了。

# 选择排序

def selSort(L):

for i in range(len(L) - 1):

minIndx = i

minVal= L[i]

j = i + 1

while j < len(L):

if minVal > L[j]:

minIndx = j

minVal= L[j]

j += 1

temp = L[i]

L[i] = L[minIndx]

L[minIndx] = temp

# 这里选择排序的时间复杂度为 O(len(L)^2),显然选择排序的效率并不高,

# 我们需要更好的排序方法

# 归并排序

# 将列表分为两部分,分别排序,然后将两个列表合并

def merge(left, right, compare):

result = []

i,j = 0, 0

while i < len(left) and j < len(right):

if compare(left[i], right[j]):

result.append(left[i])

i += 1

else:

result.append(right[j])

j += 1

while (i < len(left)):

result.append(left[i])

i += 1

while (j < len(right)):

result.append(right[j])

j += 1

return result

import operator

def mergeSort(L, compare = operator.lt):

if len(L) < 2:

return L[:]

else:

middle = int(len(L)/2)

left = mergeSort(L[:middle], compare)

right = mergeSort(L[middle:], compare)

return merge(left, right, compare)

# merge的复杂度为 O(len(L)) mergesort 的复杂度为 O(len(L) * log(len(L)))

# 简化为 O(n*log(n)) 归并排序相比于选择排序效率提高了很多,这样的效率我们可以接受

hash:

哈希的思想如下。给定一个键,比如,它指向了一个字典的一个元素。一个哈希函数会将这个键转换为一个整数,然后它用这个整数来检索列表。哈希函数可以让我们查找东西,这个查找过程的用时几乎独立于字典的规模。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值