[Python] 數據結構與算法筆記(基本結構和遞歸)

1.基本結構

線性數據結構

1.1 棧

“後進先出 LIFO” 進棧和出棧的順序正好相反
e.g. 瀏覽器的後退,word的undo
抽象數據類型“棧”是一個有次序的數據集,每個數據項僅從“棧頂”一端加入到數據集中、從數據集中移除,棧具有後進先出LIFO的特性。
在這裏插入圖片描述

1.1.1 棧的操作

基本操作:
在這裏插入圖片描述
操作例子:
在這裏插入圖片描述
在這裏插入圖片描述

Stack測試代碼:

from pythonds.basic.stack import Stack

s = Stack()

print(s.isEmpty())
s.push(4)
s.push('dog')
print(s.peek())
s.push(True)
print(s.size())
print(s.isEmpty())
s.push(8.4)
print(s.pop())
print(s.pop())
print(s.size())

result:

True
dog
3
False
8.4
True
2

1.1.2 棧的應用——簡單括號匹配

from pythonds.basic.stack import Stack

def perChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if symbol == '(':
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                s.pop()

        index += 1

    if balanced and s.isEmpty():
        return True
    else:
        return False

實際應用中,會碰到更多種括號
python中的list [],dict {},tuple和表達式 ()。

def perChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if symbol in '([{':         #加上多個左括號
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                # 括號匹配
                top = s.pop()
                if not matches(top, symbol):
                    balanced = False

        index += 1

    if balanced and s.isEmpty():
        return True
    else:
        return False


def matches(open, close):       #匹配
    opens = '([{'
    closers = ')]}'
    return opens.index(open) == closers.index(close)	#通過索引進行匹配

1.1.3 棧的應用——十進制轉換成二進制

在這裏插入圖片描述

from pythonds.basic.stack import Stack

def divideBy2(decNumber):
    remstack = Stack()

    while decNumber > 0:
        rem = decNumber % 2
        remstack.push(rem)
        decNumber = decNumber // 2   # // 整數除

    binString = ""
    while not remstack.isEmpty():
        binString = binString + str(remstack.pop())

    return binString

print(divideBy2(42))

擴展:十六進制

from pythonds.basic.stack import Stack

def baseConverter(decNumber, base):
    digits = "0123456789ABCDEF"  #十六進制
    remstack = Stack()

    while decNumber > 0:
        rem = decNumber % base          #base爲進制
        remstack.push(rem)
        decNumber = decNumber // base

    newString = ""
    while not remstack.isEmpty():
        newString = newString + digits[remstack.pop()]  # 如:pop()出14,則查表得到E

    return newString

print(baseConverter(25,16))
print(baseConverter(25,2))

1.1.4 棧的應用——表達式轉換

中綴表達式
前綴表達式
後綴表達式
在這裏插入圖片描述

算法:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

from pythonds.basic.stack import Stack

def infixToPostfix(infixexpr):
    prec = {}       #記錄操作符優先級
    prec['*'] = 3
    prec['/'] = 3
    prec['+'] = 2
    prec['-'] = 2
    prec['('] = 1

    opStack = Stack()
    postfixList = []
    tokenList = infixexpr.split()       #解析表達式到單詞列表

	# 掃描
    for token in tokenList:
        if token in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" or token in "0123456789":
            postfixList.append(token)
        elif token == '(':
            opStack.push(token)
        elif token == ')':
            topToken = opStack.pop()
            while topToken != '(':
                postfixList.append(topToken)
                topToken = opStack.pop()
        else:
            while ( not opStack.isEmpty()) and (prec[opStack.peek() ] >= prec[token]):
                postfixList.append(opStack.pop())
            opStack.push(token)

    while not opStack.isEmpty():
        postfixList.append(opStack.pop())
    return " ".join(postfixList)		#合成後綴表達式字符串

後綴表達式求值
在這裏插入圖片描述

from pythonds.basic.stack import Stack

def postfixEval(postfixExper):
    operandStack = Stack()
    tokenList = postfixExper.split()   

    for token in tokenList:
        if token in  "0123456789":
            operandStack.push(int(token))
        else:
            operand2 = operandStack.pop()       #從棧頂彈出2個操作數,先彈出的是右操作數,後彈出的是左操作數。
            operand1 = operandStack.pop()       
            result = doMath(token,operand1,operand2)
            operandStack.push(result)
    return operandStack.pop()

def doMath(op, op1, op2):
    if op == '*':
        return op1 * op2
    elif op == '/':
        return op1 / op2
    elif op == '+':
        return op1 + op2
    else:
        return op1 - op2

1.2 隊列

“先進先出 FIFO”
e.g. 進程調度(進程數遠多於CPU核心數,有些進程還要等待不同類型I/O事件),打印機,鍵盤緩存

1.2.1 隊列的操作

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

1.2.2 隊列的應用——熱土豆問題

from pythonds.basic.queue import Queue

def hotPotato(namelist, num):
    simqueue = Queue()
    for name in namelist:
        simqueue.enqueue(name)

    while simqueue.size() > 1:	#循環到隊列只剩一個
        for i in range(num):   #隊首出隊,再入隊,共循環num次
            simqueue.enqueue(simqueue.dequeue())
        simqueue.dequeue()	#隊首出隊

    return simqueue.dequeue() 	#最後唯一一個出隊輸出

# 傳遞固定人數,7
print(hotPotato(['Bill','David','Susan','Jane','Kent','Brad'],7))

1.2.3 隊列的應用——打印任務

from pythonds.basic.queue import Queue
import random

class Printer:
    def __init__(self, ppm):
        self.pagerate = ppm         #打印速度
        self.currentTask = None     #打印任務
        self.timeRemaining = 0      #任務倒計時

    def tick(self):         #打印1秒
        if self.currentTask != None:
            self.timeRemaining = self.timeRemaining - 1
            if self.timeRemaining <= 0:
                self.currentTask = None

    def busy(self):     #打印忙?
        if self.currentTask != None:
           return True
        else:
           return False

    def startNext(self,newtask):        #打印新任務
       self.currentTask = newtask
       self.timeRemaining = newtask.getPages() * 60/self.pagerate


class Task:
    def __init__(self,time):
        self.timestamp = time       #生成時間戳
        self.pages =random.randrange(1,21)      #打印頁數
 
    def getStamp(self):
        return self.timestamp
 
    def getPages(self):
        return self.pages
 
    def waitTime(self,currenttime):
        return currenttime -self.timestamp      #等待時間

 
def newPrintTask():
    num =random.randrange(1,181)        #1/180概率生成作業
    if num == 180:
        return True
    else:
        return False

def simulation(numSeconds, pagesPerMinute):     #模擬
 
    labprinter =Printer(pagesPerMinute)
    printQueue = Queue()
    waitingtimes = []
 
    for currentSecond in range(numSeconds):
 
      if newPrintTask():
          task =Task(currentSecond)
          printQueue.enqueue(task)
 
      if (not labprinter.busy()) and (not printQueue.isEmpty()):
          nexttask =printQueue.dequeue()
          waitingtimes.append(nexttask.waitTime(currentSecond))
          labprinter.startNext(nexttask)
 
      labprinter.tick()

    averageWait=sum(waitingtimes)/len(waitingtimes)
    print("Average Wait %6.2f secs %3d tasks remaining."%(averageWait,printQueue.size()))
 



#模擬10次,每次3600s,打印機每分鐘5頁
for i in range(10):
    simulation(3600,5)


Average Wait 120.17 secs 0 tasks remaining.
Average Wait 256.60 secs 2 tasks remaining.
Average Wait 48.81 secs 0 tasks remaining.
Average Wait 142.91 secs 2 tasks remaining.
Average Wait 113.92 secs 1 tasks remaining.
Average Wait 22.40 secs 2 tasks remaining.
Average Wait 119.29 secs 0 tasks remaining.
Average Wait 163.48 secs 1 tasks remaining.
Average Wait 133.04 secs 0 tasks remaining.
Average Wait 68.75 secs 0 tasks remaining.

1.3 雙端隊列抽象數據類型及Python實現+迴文詞判定

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
應用:“迴文詞”判定

from pythonds.basic.deque import Deque

# 判斷是否是迴文詞
def back_to_word_check(s1):
	deque = Deque()								#實例化雙端隊列
	[deque.addRear(i) for i in s1]				#將字符串從隊尾入隊
	while deque.size() > 1:						#隊列長度>1,則循環,否則爲0或1個,則說明是迴文詞
		first = deque.removeFront()				#從隊首出隊一個
		last = deque.removeRear()				#從隊尾出隊一個
		if first != last:						#若不相同,則
			return False 						#非迴文詞
	return True 								#迴文詞

s1 = '枯眼望遙山隔水往來曾見幾心知壺空怕酌一杯酒筆下難成和韻詩途路阻人離別久訊音無雁寄回遲孤燈夜守長寥寂夫憶妻兮父憶兒兒憶父兮妻憶夫寂寥長守夜燈孤遲迴寄雁無音訊久別離人阻路途詩韻和成難下筆酒杯一酌怕空壺知心幾見曾來往水隔山遙望眼枯'
print(back_to_word_check(s1))

1.4 無序表抽象數據類型及Python實現

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
實現
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

1.5 有序表抽象數據類型及Python實現

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

2 遞歸

2.1 遞歸與實現

將問題分解爲規模更小的相同問題
在這裏插入圖片描述
遞歸實現:
在這裏插入圖片描述
遞歸深度限制,防止無限遞歸。

import sys

sys.getrecursionlimit()		#默認限制遞歸1000

sys.getrecursionlimit(3000)		#限制遞歸3000次

2.2 遞歸的應用——任意進制轉換

def toStr(n,base):
    convertString = "0123456789ABCDEF"
    if n < base:
        return convertString[n]     #最小規模
    else:
        return toStr(n//base,base) + convertString[n%base]      #減小規模,調用自身

print(toStr(1453,16))   #將1453轉換成16進制

2.3 遞歸可視化

2.3.1 分形樹

在這裏插入圖片描述
e.g.
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述

2.3.2 謝爾賓斯基三角形

在這裏插入圖片描述

2.4 遞歸的應用——漢諾塔

在這裏插入圖片描述

def moveTower(height, fromPole, withPole, toPole):
    if height >= 1:
        moveTower(height - 1, fromPole, toPole, withPole)
        moveDisk(height, fromPole, toPole)
        moveTower(height - 1, withPole, fromPole, toPole)

def moveDisk(disk, fromPole, toPole):
    print(f"Moving disk[{disk}] from {fromPole} to {toPole}")

moveTower(3, "#1", "#2", "#3")

Moving disk[1] from #1 to #3
Moving disk[2] from #1 to #2
Moving disk[1] from #3 to #2
Moving disk[3] from #1 to #3
Moving disk[1] from #2 to #1
Moving disk[2] from #2 to #3
Moving disk[1] from #1 to #3

幾個小算法

讀取以空格分隔的一行整數

input 3個數:

# input 3個數
a,b,c = map(int, input().split())

input 未知個數:

# input未知個數
op = map(int, input().split())
l = []
l=[i for i in op]
print(min(l))

將list中的string轉換爲int

假設有這樣一個
results = [‘1’, ‘2’, ‘3’]
轉化爲下面這個樣子
results = [1, 2, 3]

results = list(map(int, results))

洗盤子

在這裏插入圖片描述

from pythonds.basic.stack import Stack

def washdishes(nums):
    s = Stack()
    index = 0
    l = []

    for num in nums:
        if s.isEmpty() or s.peek() < num:
            s.push(num)
            l.append(num)
        elif s.peek() > num and num+1 in l:
            s.push(num)
            l.append(num)
        else:
            return 'No'
            break
    return 'Yes'

int()進制轉換

    num = int(str(num), base=m) #將m進制的num轉換成十進制

進制轉換表:

2進制 8進制 10 進制 16進制
2進制 - bin(int(x,8)) bin(int(x,10)) bin(int(x,16))
8進制 oct(int(x,2)) - oct(int(x,10)) oct(int(x,16))
10進制 str(int(x,2)) str(int(x,8)) - str(int(x,16))
16進制 hex(int(x,2)) hex(int(x,8) hex(int(x,10)) -
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章