這篇博客主要記錄我在學習python算法時實現棧的過程,這裏棧的實現只是最簡單的實現,其中也包括符號匹配,前綴、中綴以及後綴表達式的實例。參考書目爲:javascript
problem-solving-with-algorithms-and-data-structure-using-python 中文版。css
運行環境:Python3.6 + Jupyter notebook。html
這篇博客至關於學習筆記,請勿轉載。html5
原文:Python3 棧的實現。java
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[-1]
def size(self):
return len(self.items)
if __name__ == '__main__':
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())
區分括號是否匹配的能力是識別不少編程語言結構的重要部分。具備挑戰的是如何編寫一個算法,可以從左到右讀取一串符號,並決定符號是否平衡。爲了解決這個問題,咱們須要作一個重要的觀察。從左到右處理符號時,最近開始符號必須與下一個關閉符號相匹配(見 Figure 1)。此外,處理的第一個開始符號必須等待直到其匹配最後一個符號。結束符號以相反的順序匹配開始符號。他們從內到外匹配。這是一個能夠用棧解決問題的線索。python
Figure 1jquery
def parChecker(symbol_sring):
s = Stack()
balanced = True
index = 0
while index < len(symbol_sring) and balanced:
symbol = symbol_sring[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
print(parChecker('((()))'))
print(parChecker('((()'))
注:棧是處理括號匹配極好的數據結構linux
def check(strings):
s = Stack()
for string in strings:
if string == '(':
s.push(string)
elif string == ')':
try:
s.pop()
except IndexError:
return False
else:
return False
return s.isEmpty()
print(check('((()))'))
print(check('()))'))
上面的兩個程序僅用於'()'的匹配,實際上 Python 中經常使用的括號有 { } [ ] ( )。符號字符串如:android
{ { ( [ ] [ ] ) } ( ) }css3
[ [ { { ( ( ) ) } } ] ]
[ ] [ ] [ ] ( ) { }
都是正確的匹配。
def check(strings):
s = Stack()
for string in strings:
if string in '{[(':
s.push(string)
elif string in ')]}':
try:
match(open=s.pop(), close=string)
except(IndexError, ValueError):
return False
else:
return False
return s.isEmpty()
def match(open, close):
opens = '{[('
closers = '}])'
if opens.index(open) != closers.index(close):
raise ValueError
print(check('[][][](){}'))
print(check('[{()]'))
首先看看 Python3 內置函數進制轉換用法
help(bin)
bin(256)
注:二進制字符串以0b開頭
oct(256)
注:八進制字符串以0o開頭
hex(256)
注:十六進制字符串以0x開頭
# 其餘進制 to 十進制
int(bin(256), 2)
int(oct(256), 8)
int(hex(256), 16)
其餘進制轉換能夠以十進制爲媒介
bin(int(oct(256), 8)) # oct2bin
基本思想是將十進制數不斷迭代除以2,並跟蹤餘數。Figure2 以二進制爲例,展現了棧是解決這個問題的數據結構。
Figure2
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[-1]
def size(self):
return len(self.items)
def __iter__(self):
for i in self.items[::-1]:
yield i
def box(dec_number, base=2):
remstack = Stack()
base_num = [str(i) for i in range(10)] + [chr(x) for x in range(ord('A'), ord('A')+6)]
prefix = 'box'
while dec_number > 0:
index = dec_number % base
remstack.push(base_num[index])
dec_number = dec_number // base
try:
return '0'+ prefix[[2, 8, 16].index(base)] + ''.join(remstack)
except ValueError:
return ''.join(remstack)
# test
print(box(233, 2))
print(box(233,3))
print(box(233,5))
print(box(233,8))
print(box(233,10))
print(box(233,16))
注:box()函數實現十進制至2到16之間任意進制轉換,可是除bin, oct, hex 外均無前綴。
咱們日常的算術表達式通常是中綴表達式,例如:A+B*C
就是中綴表達式:運算符在操做數之間。
可是如何辨別運算順序即優先級是個問題。咱們能夠用括號來明確:(A+(B*C))
。
其實,咱們能夠用前綴表達式:+ A * B C
,運算符在操做數前面緊鄰;
利用後綴表達式:A B C * +
。
這樣一來,運算符的優先級很容易體現:緊鄰的運算符優先級高。
下面討論中綴轉後綴表達式,基本思想是:
*,/,+
或 -
,將其壓入 opstack。可是,首先刪除已經在 opstack 中具備更高或相等優先級的任何運算符,並將它們加到輸出列表中。import re
def infix2postfix(infixexpr):
#肯定優先級
prec = {}
prec['('] = 1
prec['+'] = 2
prec['-'] = 2
prec['*'] = 3
prec['/'] = 3
opstack = Stack() # 存儲運算符
postfix_list = [] # 後綴表達式
token_list = [i for i in infixexpr if not re.match(r'\s+',i)]
for token in token_list:
if re.match(r'[0-9a-zA-Z]', token):
postfix_list.append(token) # 操做數加入後綴表達式
elif token == '(':
opstack.push(token) # '(' 壓入棧內
elif token == ')':
top_token = opstack.pop()
while top_token != '(':
postfix_list.append(top_token)
top_token = opstack.pop()
else:
while (not opstack.isEmpty()) and (prec[opstack.peek()] >= prec[token]):
postfix_list.append(opstack.pop())
opstack.push(token)
while not opstack.isEmpty():
postfix_list.append(opstack.pop())
return ' '.join(postfix_list)
print(infix2postfix("A * B + C * D"))
print(infix2postfix("( A + B ) * C - ( D - E ) * ( F + G )"))
基本思想以下圖:
def postfix_eval(postfix_expr):
s = Stack()
token_list = postfix_expr.split()
for token in token_list:
if re.fullmatch(r'([0-9])|([1-9][0-9]+)', token):
s.push(int(token))
else:
opra2 = s.pop()
opra1 = s.pop()
result = do_math(token, opra1, opra2)
s.push(result)
return s.pop()
def do_math(op, op1, op2):
if op == "*":
return op1 * op2
elif op == "/":
return op1 / op2
elif op == "+":
return op1 + op2
else:
return op1 - op2
print(postfix_eval('7 8 + 3 2 + /'))
zxzhu 2018/2/12
Reference: