第一部分
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)) | - |