数量级函数描述的是,当n增长时,T(n)增长最快的部分。数量级常被称为大O算法(O:order),记作O(f(n))。
2.3.1列表
#得到每个函数的执行时间:
def func1():
l = []
for x in range(1000):
l = l + [x]
import timeit#timeit模块实现跨平台计时
t1 = timeit.Timer('func1()','from __main__ import func1')#建立一个Timer对象
t = t1.timeit(number = 1000)
print("func1 needs",t,'milliseconds')
输出
func1 needs 1.8420630999999998 milliseconds
比较time和timeit
#module
import time
#time
#时间表现形式:
#timestamp:时间戳,从1970.1.1 00:00:00开始的秒计算的偏移量
#struct_time:时间元组
#format time:格式化时间,已格式化的结构使时间更具可读性。分为自定义格式和固定格式
#1.获取当前时间戳
print(time.time())
#2.获取当前时间的sturct_time形式
print(time.localtime())
#3.当前时间的字符串形式
print(time.ctime())
#4.把当前时间戳转化为字符格式
print(time.strftime('%Y-%m-%d\n%H:%M:%S',time.localtime()))
#计算程序用时time.time
def sample(n):
fac = 1
for i in range(1,n+1):
i * fac
return fac
fstart = time.time()
sample(10000)
fend = time.time()
print("{}".format(fend - fstart))
import timeit
#1.实例一个Timer对象
#timeit.Timer(需要测量的语句或函数-->str,初始化代码或构件环境的导入语句-->str)
t1 = timeit.Timer('sample(100)','from __main__ import sample')
#2.显示执行过number次的时间,默认为一百万
print(t1.timeit(number = 1000))
#.repeat(repeat-->int,number-->int)指定整个实验的重复次数,返回一个包含了每次试验的执行时间的列表)
print(t1.repeat(repeat=4,number=1000))
输出
1611645756.4645915
time.struct_time(tm_year=2021, tm_mon=1, tm_mday=26, tm_hour=15, tm_min=22, tm_sec=36, tm_wday=1, tm_yday=26, tm_isdst=0)
Tue Jan 26 15:22:36 2021
2021-01-26
15:22:36
0.0010004043579101562
0.004565700000000006
[0.004177100000000003, 0.005625499999999992, 0.005497199999999994, 0.004231799999999994]
python列表操作的大O效率
操作 | 大O效率 |
---|---|
索引 | O(1) |
索引赋值 | O(1) |
追加append() | O(1) |
pop() | O(1) |
pop(i) | O(n) |
insert(i.item) | O(n) |
删除 | O(n) |
遍历 | O(n) |
包含in | O(n) |
切片 | O(k) |
删除切片 | O(n) |
设置切片 | O(n+k) |
反转 | O(n) |
连接+ | O(k) |
排序 | O(nlogn) |
乘法 | O(nk) |
2.3.2字典
python字典操作的大O效率
操作 | 大O效率 |
---|---|
复制 | O(n) |
取值 | O(1) |
赋值 | O(1) |
删除 | O(1) |
包含 | O(1) |
遍历 | O(n) |
#匹配括号
from pythonds.basic import Stack
def patChecker(symbolstr):
idx = 0
s = Stack()
if symbolstr == '':
return True
for idx in range(len(symbolstr)):
if symbolstr[idx] == "(":
s.push(symbolstr[idx])
else:
if s.isEmpty():
return False
s.pop()
if s.isEmpty():
return True
else:
return False
#匹配括号
from pythonds.basic import Stack
def patChecker(symbolstr):
idx = 0
s = Stack()
if symbolstr == '':
return True
for idx in range(len(symbolstr)):
if symbolstr[idx] in "({[":
s.push(symbolstr[idx])
else:
if s.isEmpty():
return False
elif match(s.peek(),symbolstr[idx]):
s.pop()
elif symbolstr[idx] in "}])":
return False
if s.isEmpty():
return True
else:
return False
def match(sl,sr):
dict1 = {
'(':')','{':'}','[':']'}
if sr == dict1[sl]:
return True
return False
print(patChecker('(})'))
#用栈实现十进制转换为各种进制
from pythonds.basic import Stack
def baseconverter(decNumber,base):
digital = '0123456789ABCDEF'
s = Stack()
snum = ''
while decNumber // base != 0:
s.push(digital[decNumber % base])
decNumber = decNumber // base
s.push(digital[decNumber % base])
while not s.isEmpty() :
snum += str(s.pop())
return snum
print(baseconverter(1324535,16))
#用python实现从中序表达式到后序表达式的转换
from pythonds.basic import Stack
def infixToPostfix(infixexpr):
s = Stack()#存储标识符之一:括号
operator = Stack()#存储标识符之二:运算符号
dictspr = {
'+':0,'-':0,"*":1,"/":1}#用来比较优先级
Postfixexpr = ''#输出
for x in infixexpr:
if x in '+-*/':
if operator.isEmpty():
operator.push(x)
elif dictspr[operator.peek()] == dictspr[x] or \
dictspr[operator.peek()] > dictspr[x]:
#整理operator栈,保证优先级高的接近尾端,或者同等优先级下靠左的接近尾端
a = operator.pop()
operator.push(x)
operator.push(a)
if s.isEmpty():#如果没有括号,那么按照逻辑顺序添加输出
Postfixexpr += operator.pop()
else:#operator栈存在运算符并且按照逻辑顺序,优先级高的接近尾端
if s.isEmpty:#如果没有括号,那么在运算符栈添加该运算符
operator.push(x)
elif x == '(':#遇到(,在s栈占位
s.push(x)
elif x == ')':#遇到),弹出对应的(,并且标志着可以在输出中添加括号内的运算符
s.pop()
if s.isEmpty():#如果s中的括号全部弹出,则代表括号内的符号应该全部输出完毕
while not operator.isEmpty():
Postfixexpr += operator.pop()
else:#证明还在括号内,只添加消除的该括号包含的运算符
Postfixexpr += operator.pop()
else:#字母,操作数
Postfixexpr += x
while not operator.isEmpty():#输出干净
Postfixexpr += operator.pop()
return Postfixexpr
print(infixToPostfix('(A-B*D)*C'))
from pythonds.basic import Stack
def postfixEval(postfixExpr):
s = Stack()
for x in postfixExpr:
if x in '+-*/':
a = s.pop()
b = s.pop()
c = eval(a+x+b)
s.push(str(c))
else:
s.push(x)
return s.pop()
print(postfixEval('3456++*'))
#传土豆模拟程序
from pythonds.basic import Queue
def hotpotato(namelist,num):
q = Queue()
for x in namelist:
q.enqueue(x)
while not q.isEmpty():
for x in range(num):
a = q.dequeue()
q.enqueue(a)
b = q.dequeue()
return b
print(hotpotato(['a','g','b','c','d'],100009))
#打印任务模拟
class Printer:
def __init__(self,speed):
self.speed = speed#页/min
self.taskWorking = None
self.currentTime = 0
self.processTime = 0
def Tick(self):#减量计时⭐
if self.taskWorking != None:
if self.processTime > 0:
self.processTime -= 1
else:
self.taskWorking = None
def Busy(self):
if self.taskWorking != None:
return True
else:
return False
def startNewone(self,taskFirst):
self.taskWorking = 1
return self.currentTime
def processTimefunc(self,taskFirst):
self.processTime = taskFirst.pages * 60 / self.speed
return self.processTime
class Task:
def __init__(self,time):
import random
self.pages = random.randint(1,20)
self.timeStamp = time
def getPages(self):
return self.pages
def getStamp(self):
return self.timeStamp
def waitingTime(self,currentTime):
return currentTime - self.timeStamp
def main():
import random
from pythonds.basic import Queue
printQueue = Queue()
printer = Printer(5)
TotalSeconds = 3600
taskid = 1
for curSecond in range(TotalSeconds):
if random.randint(1,120) == 120:
onetask = Task(curSecond)
printQueue.enqueue(onetask)
if not printQueue.isEmpty() and not printer.Busy():
oldone = printQueue.dequeue()
taskid += 1
waitingTime = oldone.waitingTime(curSecond)
printer.startNewone(oldone)
processTime = printer.processTimefunc(oldone)
print('Task{
}: wait {
} seconds and process {
:.0f} seconds,there still\
{
} tasks remaining'.format(taskid,waitingTime,processTime,printQueue.size()))
elif printer.Busy():
printer.Tick()
elif printQueue.isEmpty():
continue
main()
输出
ask1: wait 0 seconds and process 180 seconds,there still 0 tasks remaining
Task2: wait 135 seconds and process 96 seconds,there still 1 tasks remaining
Task3: wait 220 seconds and process 180 seconds,there still 0 tasks remaining
Task4: wait 60 seconds and process 204 seconds,there still 0 tasks remaining
Task5: wait 0 seconds and process 180 seconds,there still 0 tasks remaining
Task6: wait 55 seconds and process 120 seconds,there still 1 tasks remaining
Task7: wait 143 seconds and process 132 seconds,there still 0 tasks remaining
Task8: wait 25 seconds and process 72 seconds,there still 0 tasks remaining
Task9: wait 0 seconds and process 132 seconds,there still 0 tasks remaining
Task10: wait 0 seconds and process 144 seconds,there still 0 tasks remaining
Task11: wait 68 seconds and process 192 seconds,there still 2 tasks remaining
Task12: wait 229 seconds and process 228 seconds,there still 1 tasks remaining
Task13: wait 437 seconds and process 216 seconds,there still 0 tasks remaining
Task14: wait 67 seconds and process 204 seconds,there still 0 tasks remaining
Task15: wait 185 seconds and process 156 seconds,there still 0 tasks remaining
Task16: wait 149 seconds and process 192 seconds,there still 3 tasks remaining
Task17: wait 264 seconds and process 24 seconds,there still 3 tasks remaining
Task18: wait 257 seconds and process 228 seconds,there still 2 tasks remaining
Task19: wait 480 seconds and process 96 seconds,there still 5 tasks remaining
from pythonds.basic import Deque#双端列表
d = Deque()
d.isEmpty()
d.addRear(4)
d.addFront('dog')
d.size()
front = d.removeFront()
rear = d.removeRear()
#回文检测器
from pythonds.basic import Deque
def palChecker(oneStr):
d = Deque()
for chr in oneStr:
d.addRear(chr)
stillEqual = True
while d.size() > 1 and stillEqual:
first = d.removeFront()
last = d.removeRear()
if first != last:
stillEqual = False
return stillEqual
print(palChecker('abceba'))
3.6.2无序列表:链表
#实现无序列表:链表
class Node:#节点:包含节点的数据和指向下一个节点的引用
def __init__(self,initdata):
self.data = initdata
self.next = None
def getData(self):
return self.data
def setData(self,newdata):
self.data = newdata
def getNext(self):
return self.next
def setNext(self,newnext):
self.next = newnext
class UnorderedList:
def __init__(self):
self.head = None
def isEmpty(self):
if self.head == None:
return True
else:
return False
def add(self,item):
temp = Node(item)
temp.setNext(self.head)
self.head = temp
def length(self):
count = 0
current = self.head
while current != None:
current = current.getNext()
count += 1
return count
def search(self,target):
current = self.head
found = false
while current != None and not found:
if current.getData() == target:
found = True
else:
current = current.getNext()
return found
def remove(self,target):
previous = None
current = self.head
found = False
while current != None and not found:
if current.getData() == target:
found = True
if previous == None:
self.head = current.getNext()
else:
previous.setNext() = current.getNext()
else:
previous,current = current,current.getNext()
3.6.3.有序列表
- 递归算法必须有基本情况
- 递归算法必须改变其状态并向基本情况靠近
- 递归算法必须递归地调用自己
#递归
#将整数转换为任意进制的字符串
def toStr(n,base):
convertString = '0123456789ABCDEF'
if n < base:
return convertString[n]
return toStr(n//base,base) + convertString[n%base]
print(toStr(7816,16))
#栈帧:实现递归
#将整数转换成任意进制的字符串
from pythonds.basic import Stack
s = Stack()
def toStr(n,base):
convertString = '0123456789ABCDEF'
if n < base:
return s.push(convertString[n])
else:
s.push(convertString[n%base])
toStr(n//base,base)
toStr(1234,16)
r = ''
while not s.isEmpty():
r += s.pop()
print(r)
#用turtle模块递归地绘制螺旋线
from turtle import*
myturtle = Turtle()
mywin = myturtle.getscreen()
def drawSpiral(myturtle,drawline):
if drawline >= 0:
myturtle.forward(drawline)
myturtle.left(90)
drawSpiral(myturtle,drawline -5)
drawSpiral(myturtle,100)
mywin.exitionclick()
#用turtle模块递归地绘制螺旋线
from turtle import*
import random
t = Turtle()
mywin = t.getscreen()
t.left(90)
t.penup()
t.backward(250)
t.pendown()
t.speed(0)
def Tree(branchLength,t):
import random
if branchLength > 5:
t.forward(branchLength)
t.right(20)
Tree(branchLength-15,t)
t.left(40)
Tree(branchLength-10,t)
t.right(20)
t.backward(branchLength)
Tree(110,t)
mywin.exitionclick()
#谢尔平斯基三角形
from turtle import *
t = Turtle()
def drawTriangle(points,color,t):
t.fillcolor(color)
t.begin_fill()
t.up()
t.goto(points[0])
t.down()
t.goto(points[1])
t.goto(points[2])
t.goto(points[0])
t.end_fill()
def getmid(p1,p2):
return((p1[0] + p2[0])/2,(p1[1] + p2[1])/2)
def sierpinski(points,degree,t):
color = ['#ee3f4d','#f0a1a8','#fecc11',\
'#8abcd1','green']
color.reverse()
drawTriangle(points,color[degree-1],t)
if degree > 0:
sierpinski((points[0],getmid(points[0],points[1]),getmid(points[0],points[2])),degree - 1,t)
sierpinski((points[1],getmid(points[1],points[0]),getmid(points[1],points[2])),degree - 1,t)
sierpinski((points[2],getmid(points[2],points[0]),getmid(points[2],points[1])),degree - 1,t)
mywin = t.getscreen()
points = ((-500,-250),(0,500),(500,-250))
sierpinski(points,5,t)
mywin.exitionclick()
n = 5 : 如果我们知道如何把上面4个盘子移动到第二根柱子,那么就能轻易地把最底下的盘子移动到第三根柱子上,然后将4个盘子从第二根柱子移动到第三根柱子上
#汉诺塔
def HanoTower(n,a,b,c):
#将n个盘子从a柱子移动到c柱子
if n == 1:
print('{}--->{}'.format(a,c))#防止混淆:从第一根柱子移动到第三根柱子
return None#不要忘记返回
HanoTower(n-1,a,c,b)#将n-1个盘子从a柱子移动到b柱子
print('{}--->{}'.format(a,c))#将最大的盘子从a柱子移动到c柱子
HanoTower(n-1,b,a,c)#将n-1个盘子从b柱子移动到c柱子
HanoTower(6,'A','B','C')
待做
优化问题:
找到两点之间的最短路径,为一组数据点找到最佳拟合线,找到满足一定条件的最小对象集合……
解决优化问题的策略方法之一,动态规划
贪婪算法——试图最大程度地解决问题
得到最优解的方法之一——递归
找零63分,面值有1,5,10,25分
复杂,不推荐,感受思想
每一个节点都对应着一次对recMC的调用
该算法把大量时间和资源浪费在了重复计算已有的结果上在这里插入代码片
#找零问题的递归解决方法
#感受递归的复杂
def recMC(coinValuelist,ichange):
"return the minimum coins' number"
numcoins = 0
maxcoins = ichange
if ichange in coinValuelist:
return 1
else:
for x in [i for i in coinValuelist if i <= ichange]:
numcoins = 1 + recMC(coinValuelist,ichange-x)
return numcoins if numcoins < maxcoins else maxcoins
print(recMC([1,5,10,25],23))
非动态规划,而是通过记忆化(缓存)的方法来优化程序的性能
#添加查询表之后的找零算法
def recMC(coinValuelist,ichange,knowResults):
"return the minimum coins' number"
numcoins = 0
mincoins = ichange
if ichange in coinValuelist:
knowResults[ichange] = 1
return 1
elif knowResults[ichange-1] != 0:
return knowResults[ichange]
else:
for x in [i for i in coinValuelist if i <= ichange]:
numcoins = 1 + recMC(coinValuelist,ichange-x,knowResults)
if numcoins < mincoins:
mincoins = numcoins
knowResults[ichange-1] = mincoins
return numcoins
print(recMC([1,5,10,25],24,[0]*26))