本文主要是对于北京大学的基于python的数据结构和算法课程中代码的实现。结构为首先自写代码,然后进行debug并和标准代码对比,分析所写不足。以加深对python特有数据结构的理解。
python中的栈的实现如下。
class Stack():
def __init__(self):
self.items = []
def push(self,x):
self.items.append(x)
def pop(self):
popthing = self.items.pop()
return popthing
def peek(self):
return self.items[len(self.items) - 1]
def isempty(self):
return self.items == []
def size(self):
return len(self.items)
栈的应用一(括号匹配问题):
基础思想为:括号匹配:
1.循环检查输入的字符串:
检查到左括号则入栈,检查到右括号则判断栈顶是否为空,若为空则右括号多余,栈顶不为空则pop栈顶元素,若栈顶元素为非左括号,则丢弃,若为左括号则匹配,然后继续按此规则检查字符串
2.循环结束后:
检查栈是否为空,若为空则匹配过程成功,若不为空则存在多余左括号
自写代码如下
def Bracketchecker(alist):
BracketStack = Stack()
for item in alist:
if item == '(':
BracketStack.push(item)
if item == ')':
if BracketStack.isempty:
print('exist additional right bracket')
break
else:
BracketStack.pop()
if BracketStack.isempty():
return True
else:
print('exist additional left bracket')
return False
a = '(())'
Bracketchecker(a)
产生bug:
和标准代码对比后分析原因:
对python中的列表(list)的for循环理解不足。for循环非类C语言中的简单循环,而是在循环中同步对所循环列表做出的“更新”。
在遍历的过程中,删除了其中一个元素,导致后面的元素整体前移,故有个元素成了漏网之鱼。同样的,在遍历过程中,使用插入操作,也会导致类似的错误。
因此通常不在for循环中修改循环元素(修改操作包括列表元素的插入和删除)如果非要进行类似操作,可以采用提前进行切片或复制的for循环:
例如。
for i in black_list[:]:
black_list.pop(0)
print(black_list)
修改方法为用while循环代替for循环,最后附上标准代码:
def parChecker(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 = index + 1
if balanced and s.isEmpty():
return True
else:
return False
class Bracketchecker():
def match(self,open,close):
opens = '([{'
closes = ')]}'
return opens.index(open) == closes.index(close)
def parChecker(self,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:
topthing =s.pop()
if not self.match(topthing,symbol):
banlanced = False
index = index + 1
if balanced and s.isempty():
return True
else:
return False
b = Bracketchecker()
print(b.parChecker('{[()]}'))
此处的巧妙为方法match,即如何将不同括号的匹配过程分开匹配。
class BinaryBewteenDecimal():
def BtoD(self,blist):
result = 0
index = 0
s = Stack()
for item in blist:
s.push(item)
while not s.isempty():
result += int(s.pop())*2**(index)
index += 1
return result
def DtoB(self,dec):
result = ''
if dec:
result = self.DtoB(dec // 2)
return result + str(dec % 2)
else:
return result
b = BinaryBewteenDecimal()
print(b.BtoD('110011'))
print(b.DtoB(51))
def baseConverter(decNumber,base):
digits = "0123456789ABCDEF"
s = Stack()
while decNumber > 0:
rem = decNumber % base
s.push(rem)
decNumber = decNumber // base
newString = ""
while not s.isempty():
newString = newString + digits[s.pop()]
return newString
print(baseConverter(25,16))
算法思想:
1.从左到右扫描中缀表达式单词列表,如果单词是操作数,则直接添加到后缀表达式列表的末尾;如果单词是左括号,则压入opstack栈顶;如果单词是右括号,则反复弹出opstack栈顶操作符,加入到输出列表末尾,直到碰到左括号;如果单词是操作符,则压入opstack栈顶,但在压入栈顶之前,要比较其与栈顶操作符的优先级,如果栈顶的高于或等于它,就要反复弹出栈顶操作符,加入到输出列表末尾;直到栈顶的操作符优先级低于它。
2.中缀表达式单词列表扫描结束后,把opstack栈中的所有剩余操作符
依次弹出,添加到输出列表末尾。
3.把输出列表再用join方法合并成后缀表达式字符串,算法结束。
def InfixToPostfix(infix):
pre = {}
pre['*'] = 3
pre['/'] = 3
pre['+'] = 2
pre['-'] = 2
pre['('] = 1
pre[')'] = 1
s = Stack()
postinfix = []
tokenlist = infix.split()
for item in tokenlist:
if item in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' or item in "01234567890":
postinfix.append(item)
elif item == '(':
s.push(item)
elif item == ')':
while not s.peek() == '(':
postinfix.append(s.pop())
s.pop()
else:
while pre[s.peek()] >= pre[item]:
postinfix.append(s.pop())
s.push(item)
while not s.isempty():
postinfix.append(s.pop())
result = "".join(postinfix)
开始未想到用字典的方式便利储存操作符的优先级,在括号的处理上不够巧妙,没有在‘)’情况中反复弹出栈顶元素时,考虑栈空的条件。借鉴了标准代码对操作数的 if。
下面借鉴标准代码,写出中缀表达式转后缀表达式的过程和后缀表达式计算的过程,并在标准代码基础上写成一个类
后缀表达式计算的思想:
1.创建空栈operandStack用于暂存操作数。
2.将后缀表达式用split方法解析为单词(token)的列表。
3.从左到右扫描单词列表,如果单词是一个操作数,将单词转换为整数int,压入operandStack栈顶;如果单词是一个操作符,就开始求值,从栈顶弹出两个操作数,先弹出的是右操作数,后弹出的是左操作数,计算后将值重新压入栈顶。
4.单词列表扫描结束后,表达式的值就在栈顶。
5.弹出栈顶的值,返回。
class Postfix():
def InfixToPostfix(self,infix):
pre = {}
pre['*'] = 3
pre['/'] = 3
pre['+'] = 2
pre['-'] = 2
pre['('] = 1
pre[')'] = 1
s = Stack()
postinfix = []
tokenlist = infix.split()
for item in tokenlist:
if item in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' or item in "01234567890":
postinfix.append(item)
elif item == '(':
s.push(item)
elif item == ')':
topthing = s.pop()
while topthing != '(':
postinfix.append(topthing)
topthing = s.pop()
else:
while (not s.isempty())and([s.peek()] >= pre[item]):
postinfix.append(s.pop())
s.push(item)
while not s.isempty():
postinfix.append(s.pop())
result = "".join(postinfix)
def CaculatePostfix(self,postinfix):
operandStack = Stack()
tokenList = postinfix.split()
for token in tokenList:
if token in "0123456789":
operandStack.push(int(token))
else:
operand2 = operandStack.pop()
operand1 = operandStack.pop()
result = self.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