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

  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()

《Python数据结构与算法分析》知识点个体化_第1张图片

  • 谢尔平斯基三角形
#谢尔平斯基三角形
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()

《Python数据结构与算法分析》知识点个体化_第2张图片

  • 汉诺塔

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. 用动态规划算法解决找零问题

《Python数据结构与算法分析》知识点个体化_第3张图片

《Python数据结构与算法分析》知识点个体化_第4张图片

《Python数据结构与算法分析》知识点个体化_第5张图片

  1. 修改后的动态规划解法

你可能感兴趣的:(Python数据结构与算法分析,python,数据结构)