《Python数据结构与算法分析》知识点个体化

1.Python基础

2.算法分析

数量级函数描述的是,当n增长时,T(n)增长最快的部分。数量级常被称为大O算法(O:order),记作O(f(n))。

2.3Python数据结构的性能

2.3.1列表

  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)
包含inO(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 递归三原则

  1. 递归算法必须有基本情况
  2. 递归算法必须改变其状态并向基本情况靠近
  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)

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分

  1. 找零问题的递归解决方案

复杂,不推荐,感受思想
每一个节点都对应着一次对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))
  1. 添加查询表之后的找零算法

非动态规划,而是通过记忆化(缓存)的方法来优化程序的性能

#添加查询表之后的找零算法
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))

  1. 用动态规划算法解决找零问题

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

 #用动态规划解决找零问题
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,[])) 
  1. 修改后的动态规划解法

第五章 搜索与排序

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))
  1. 二分搜索

时间复杂度:O(logn)
n / 2 i = 1 n/2^i = 1 n/2i=1 --> i = l o g n i = logn i=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
  1. 散列⭐

时间复杂度:O(1)
散列表是元素集合,散列表中的每个位置通常被称为槽,大小尽量为素数(大小:11,跨步:加3,可以保证表中所有的槽最终被访问到)bb
散列函数将散列表中的元素与其所属的位置对应起来
载荷因子 λ = ( 元 素 个 数 ) / ( 散 列 表 大 小 ) λ = (元素个数)/(散列表大小) λ=/
冲突

  1. 散列函数:
    冲突数最少,计算方便,元素均匀分布在散列表中。
    折叠法、平方取中法、

5.3 排序

  1. 冒泡排序

时间复杂度:O( n 2 n^2 n2)

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
  1. 选择排序

时间复杂度:O( n 2 n^2 n2)
较冒泡排序更快

#选择排序
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
  1. 插入排序

时间复杂度:O( n 2 n^2 n2)

原理:在列表较低的一端维护一个有序的子列表,并逐个将每个新元素“插入”这个子列表。
交换操作的处理时间约是移动操作的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
  1. 希尔排序

时间复杂度:O( n 3 / 2 ) n^{3/2}) n3/2))

比较次数和交换次数与插入排序相比大大降低

步骤:1.分组+插入排序(i:步长。 i 1 i_1 i1 = 总长//2, i 2 = i 1 / 2 i2 = i_1/2 i2=i1/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
  1. 归并排序

时间复杂度: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搜索与回溯算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值