1.Python基础
2.算法分析
数量级函数描述的是,当n增长时,T(n)增长最快的部分。数量级常被称为大O算法(O:order),记作O(f(n))。
2.3Python数据结构的性能
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) |
3.线性数据类型
3.3栈
- LIFO(Last in first out)
- 匹配括号
#匹配括号
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实现从中序表达式到后序表达式的转换
#用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'))
- 用python实现后序表达式的计算
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++*'))
3.4队列
- FIFO(First in first out)
- 传土豆模拟程序
#传土豆模拟程序
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
3.5双端队列
- 操作
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列表
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.有序列表
4.递归
4.2 递归三原则
- 递归算法必须有基本情况
- 递归算法必须改变其状态并向基本情况靠近
- 递归算法必须递归地调用自己
- 将整数转换成任意进制的字符串
#递归
#将整数转换为任意进制的字符串
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)
4.4递归可视化
- 用turtle模块递归地绘制螺旋线
#用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')
4.6探索迷宫
待做
4.7动态规划
优化问题:
找到两点之间的最短路径,为一组数据点找到最佳拟合线,找到满足一定条件的最小对象集合……解决优化问题的策略方法之一,动态规划
贪婪算法——试图最大程度地解决问题
得到最优解的方法之一——递归
- 找零问题:
找零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))
- 用动态规划算法解决找零问题
#用动态规划解决找零问题
def dpMakerChange(coinValueList,change,mincoins):
for cents in range(change+1):
coinNumber = cents
for x in [c for c in coinValueList if c <= cents]:
if mincoins[cents - x] + 1 < coinNumber:
coinNumber = mincoins[cents - x] + 1
mincoins.append(coinNumber)
return mincoins[-1]
print(dpMakerChange([1,5,10,25],22,[]))
- 修改后的动态规划解法
第五章 搜索与排序
5.2搜索
时间复杂度:O(n)
#有序列表的顺序搜索:
def orderedSequentialSerch(alist,item):#if in?
pos = 0
found = False
stop = False
alist.sort()
while pos < len(alist) and not stop and not found:
if alist[pos] == item:
found = True
elif alist[pos] > item:
stop = True
else:
pos += 1
return found
print(orderedSequentialSerch([1,2,3,4,2,1,3],8))
- 二分搜索
时间复杂度:O(logn)
-->
#有序列表的二分搜索
def binarySearch(alist,item):
first = 0
last = len(alist) - 1
found = False
while first <= last and not found:
midpos = (first+last) // 2
if alist[midpos] == item:
found = True
else:
if alist[midpos] < item:
first = midpos + 1
else:
last = midpos - 1
return found
#二分搜索的递归版本
def binarySearch(alist,item):
first = 0
last = len(alist) - 1
found = False
while first <= last and not found:
midpos = (first+last) // 2
if alist[midpos] == item:
found = True
else:
if alist[midpos] < item:
return binarySearch(alist[midpos+1:],item)
else:
return binarySearch(alist[:midpos],item)
return found
- 散列⭐
时间复杂度:O(1)
散列表是元素集合,散列表中的每个位置通常被称为槽,大小尽量为素数(大小:11,跨步:加3,可以保证表中所有的槽最终被访问到)bb
散列函数将散列表中的元素与其所属的位置对应起来
载荷因子
冲突
- 散列函数:
冲突数最少,计算方便,元素均匀分布在散列表中。
折叠法、平方取中法、
5.3 排序
- 冒泡排序
时间复杂度:O(
)
def bubbleSort(alist):
for passnum in range(len(alist)-1,0,-1):#从最后一位到倒数第二位,慢慢冒泡的passnum
for i in range(passnum):#产生passnum位置上的数字要比较passnum次
if alist[i + 1] < alist[i]:
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
return alist
- 选择排序
时间复杂度:O(
)
较冒泡排序更快
#选择排序
def selctionSort(alist):
positionOfmax = 0
for fillslot in range(len(alist)-1,0,-1):
for location in range(0,fillslot):
if alist[location] > alist[positionOfmax]:
positionOfmax = location
alist[positionOfmax],alist[fillslot] = alist[fillslot],alist[positionOfmax]
return alist
- 插入排序
时间复杂度:O(
)
原理:在列表较低的一端维护一个有序的子列表,并逐个将每个新元素“插入”这个子列表。
交换操作的处理时间约是移动操作的3倍。在基准测试中,插入排序算法的性能很不错。
#插入排序
def insertionSort(alist):
for pos in range(1,len(alist)):
currentvalue = alist[pos]
while pos > 0 and alist[pos-1] > currentvalue:
alist[pos] = alist[pos-1]#移动操作
pos -= 1
alist[pos] = currentvalue
return alist
- 希尔排序
时间复杂度:O(
)
比较次数和交换次数与插入排序相比大大降低
步骤:1.分组+插入排序(i:步长。
= 总长//2,
,–>i = 1)
2.当i = 1时,对总体进行插入排序
#希尔排序
def shellSort(alist):
sublistcount = len(alist) // 2
while sublistcount > 0:
for startpos in range(sublistcount):
gapInsertionSort(alist,startpos,sublistcount)
sublistcount //= 2
return alist
def gapInsertionSort(alist,start,gap):
for i in range(start+gap,len(alist),gap):
curvalue = alist[i]
while i >= gap and curvalue < alist[i-gap]:
alist[i] = alist[i - gap]
i = i - gap
alist[i] = curvalue
- 归并排序
时间复杂度:O(nlogn)使用分治策略改进排序算法归并排序时递归算法
#归并排序
def mergeSort(alist):
if len(alist) == 1:
return alist
mid = len(alist) // 2
leftlist = alist[:mid]
rightlist = alist[mid:]
alist[:mid] = mergeSort(leftlist)#注意这里要改变alist
alist[mid:] = mergeSort(rightlist)
i,j,k = 0,0,0
while i < len(leftlist) and j < len(rightlist):#当左右子列都没有全部排列上去时
if leftlist[i] < rightlist[j]:
alist[k] = leftlist[i]
i += 1
else:
alist[k] = rightlist[j]
j += 1
k += 1
while i < len(leftlist):#当左子列还剩一个,右子列完成时
alist[k] = leftlist[i]
i += 1
k += 1
while j < len(rightlist):#当右子列还剩一个,左子列完成时
alist[k] = rightlist[j]
j += 1
k += 1
return alist #注意返回
- mergeSort()需要空间来储存切片操作得到的两半部分,当列表较大时,使用额外的空间可能会时排序出现问题。
- 快速排序
时间复杂度:O(nlogn)
快速排序算法不需要像归并排序算法那样使用额外的储存空间
#快速排序
def quickSort(alist):
quickSortHelper(alist,0,len(alist)-1)
return alist
def quickSortHelper(alist,first,last):
if first < last:
splitpoint = patition(alist,first,last)
quickSortHelper(alist,first,splitpoint-1)
quickSortHelper(alist,splitpoint+1,last)
def patition(alist,first,last):
pivot = alist[first]
L = first + 1
R = last
done = False
while not done:#直到R<L
while L <= R and alist[L] <= pivot:
L += 1
while R >= L and alist[R] >= pivot:
R -= 1
if L > R:#证明L位置左边的元素全部小于pivot,R右边的元素全部大于pivot
done = True
else:#L<R-->不会=,证明证明L位置左边的元素全部小于pivot,R右边的元素全部大于pivot,而alist[L] > pivot > alist[R]
temp = alist[L]#交换L处和R处的元素
alist[L] = alist[R]
alist[R] = temp
temp = alist[first]#[44,12,34(R),56(L),78] --> [12,34,44(R),56(L),78]
alist[first] = alist[R]
alist[R] = temp
return R
第6章 树
6.4实现
- 列表之列表
#二叉树,列表之列表
def BinaryTree(r):#创建一个二叉树实例
return [r,[],[]]#要给树添加左子树,需要在列表的第二个位置加入一个新列表,请务必当心
#如果列表的第二个位置为不空,我们要保留已有内容,并把它作为新左子树的左子树
def insertLeft(root,newbranch):#插入左子树
#root-->根的二叉树实例,不是指根的值
t = root.pop(1)
if len(t) > 0:
root.insert(1,[newbranch,t,[]])
else:
root.insert(1,[newbranch,[],[]])
def insertRight(root,newbranch):#插入右子树
#root-->根的二叉树实例,不是指根的值
t = root.pop(2)
if len(t) > 0:
root.insert(2,[newbranch,[],t])
else:
root.insert(2,[newbranch,[],[]])
#树的访问函数
def getrootVal(root):
return root[0]
def setrootVal(root,Val):
root[0] = Val
def getleftChild(root):
return root[1]
def getrightChild(root):
return root[2]
r1 = BinaryTree(18)
insertLeft(r1,3)
insertRight(r1,6)
insertLeft(r1,9)
insertRight(r1,2)
print(r1)
输出
[18, [9, [3, [], []], []], [2, [], [6, [], []]]]
- 节点与引用
class Binarytree:
def __init__(self,rootObj):
self.key = rootObj
self.leftChild = None
self.rightChild = None
def insertLeft(self,newNode):
if self.leftChild == None:
self.leftChild = newNode
else:
t = Binarytree(newNode)
t.leftChild = self.leftChild
self.leftChild = t
def insertRight(self,newNode):
if self.leftChild == None:
self.leftChild = newNode
else:
t = Binarytree(newNode)
t.rightChild = self.rightChild
self.rightChild = t
def getrightChild(self):
return self.rightChild
def getleftChild(self):
return self.leftChild
def setrootVal(self,newVal):
self.key = newVal
def getrootVal(self):
return self.key
r = Binarytree('Wang Junyi')
r.insertLeft('left hand')
r.insertRight('Right hand')
r.insertLeft('neck')
r.insertRight('neck')
print(r.getleftChild().getleftChild())
输出
left hand
6.5 二叉树的应用
- 解析树
解析树构建器
#创建树解析器
from pythonds.basic import Stack
from pythonds.trees import BinaryTree
def buildParseTree(exp):
explist = [x for x in exp]
aTree = BinaryTree('')
tstack = Stack()
currentTree = aTree
for x in explist:
if x == '(':
currentTree.insertLeft('')
tstack.push(currentTree)#在沉入子树之前,将父树压入栈中
currentTree = aTree.getLeftChild()
elif x not in '+-*/)':
currentTree.setRootVal(eval(x))
father = tstack.pop()
currentTree = father
elif x in '+-*/':
currentTree.setRootVal(x)
currentTree.insertRight('')
tstack.push(currentTree)
currentTree = currentTree.getRightChild()
elif x == ')':
if not tstack.isEmpty():
currentTree = tstack.pop()
else:
print("WRONG:"+x)
return aTree
t = buildParseTree('(3+(4*5))')
print(t.getRightChild().getRootVal())
输出
*
计算二叉解析树的递归函数
#计算二叉解析树的递归函数
def evaluate(parseTree):
opers = {'+':operator.add,'-':operator.sub,\
"/":operator.truediv,'*':operator.mul}
left = parseTree.getLeftChild()
right = parseTree.getRightChild()
if left and right:
fn = opers[parseTree.getRootVal()]
return fn(evaluate(left),evaluate(right))
else:
return parseTree.getRootVal()
import operator
from atree import t
print(evaluate(t))
- 树的遍历
前序遍历
#前序遍历
def preorder(tree):
if tree:#到叶子结束
print(tree.getRootVal())
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
#BinaryTree类下的前序遍历方法
def preorder(self):
print(self.key)
if self.leftChild:
self.leftChild.preorder()
if self.rightChild:
self.rightChild.preorder()
后序遍历
#后序遍历
def preorder(tree):
if tree:#到叶子结束
preorder(tree.getLeftChild())
preorder(tree.getRightChild())
print(tree.getRootVal())
#后序求值函数
def postordereval(atree):
opers = {'+':operator.add,'-':operator.sub,\
"/":operator.truediv,'*':operator.mul}
num1 = None
num2 = None
if atree:
num1 = postordereval(atree.getLeftChild())
num2 = postordereval(atree.getRightChild())
if num1 and num2:
return opers[atree.getRootVal()](num1,num2)
else:
return atree.getRootVal()
import operator
from atree import t
print(postordereval(t))
中序遍历
#中序遍历
def inorder(atree):
if atree != None:
inorder(atree.getLeftChild())
print(atree.getRootVal())
inorder(atree.getRightChild())
#修改后的中序遍历函数,他能完全还原括号表达式
def inorderexp(atree):
exp = ''
if atree:
exp = '(' + inorderexp(atree.getLeftChild())
exp = exp + str(atree.getRootVal())
exp = exp + inorderexp(atree.getRightChild()) + ')'
return exp
6.6利用二叉堆实现优先级队列
6.7搜索与回溯算法