目录
栈的实现
栈Stack:一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端。
一端叫栈 “ 顶top ” ,另一端叫栈 “ 底base ”。
栈的特性:反转次序。
在栈中数据,通常称为 “ 先进后出 ” 或 “ 后进先出 (Last in First out)” 。
如:浏览器后退键,先退出最新访问的网页。代码的撤销键,先撤销最近输入代码。
抽象数据类型Stack
“ 栈 ”(Stack)是一个有次序的数据集,每个数据项仅从 “ 栈顶 ” 加入数据集中。
“ 栈 ”的定义操作:
Stack() : 创建一个空栈,不包含任何数据项。
push(item) : 将item加入栈顶,无返回值。
pop() : 将栈顶数据移除,并返回栈被修改。
peek() : 查看栈顶数据,返回栈顶数据,不修改栈。
isEmpty() : 返回栈是否为空栈。
size() : 返回栈中有多少个数据项。
用python实现 ADT Stack
步骤:
1 . 将 ADT Stack 实现为 python 的 Class 。
2 . 将 ADT Stack 的操作实现成 Class 的方法。
3 . 因为 Stack 是一个数据集,我们选用最常见的数据集 List 实现。
(可以将 List 任意一端(index=0或1)设置为栈顶)
实现代码。
class Stack:
def __init__(self): # 创建一个空栈
self.items = []
def isEmpty(self): # 返回栈是否为空
return self.items == []
def push(self, item): # 将item加入栈
self.items.append(item)
def pop(self): # 将栈顶数据移除
return self.items.pop()
def peek(self): # 查看栈顶数据
return self.items[len(self.items) - 1]
def size(self): # 返回栈中有多少个数据
return len(self.items)
测试代码。
def main():
s = Stack()
print(s.isEmpty())
s.push(1)
s.push(2)
s.push('jiang')
print(s.isEmpty())
print(s.peek())
s.size()
print(s.pop())
print(s.pop())
print(s.pop())
print(s.size())
栈的应用
十进制转化为二进制
所谓 “ 进制 ” 就是用多少个字符来表示整数。
十进制就是 0 ~ 9 这是个数字字符表示,二进制就是0,1两个字符表示。
十进制转化为二进制采用 “ 除以2 求余数” 的算法。
流程 :
除二的过程,得到的余数是从低到高的顺序,但输出测试从高到低,所以使用栈。
代码实现。
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
十进制转换为二进制的算法,很容易可以扩展为转换为任意N进制,只需要将 “ 除以2 求余数 ” 改为 “ 除以N 求余数 ” 就可以了。
例:十进制转换为十六进制以下实现代码。
def baseCoverter(decnumber, base):
digits = "0123456789ABCDEF"
remstack = Stack()
while decnumber > 0:
rem = decnumber % base
remstack.push(rem)
decnumber = decnumber // base
newstring = ""
while not remstack.isEmpty():
newstring = newstring + digits[remstack.pop()]
return newstring
中缀表达法:A+B 前缀表达法:+AB 后缀表达法:AB+
中缀表达式 ( A + B ) * C 按照转换规则前缀表达式 “ +AB * C” , 后缀表达式 “ AB+C * ” 。
因为在前缀后缀表达式中,操作符的次序完全决定了运算的次序,所以在很多情况下,表达式的计算机表示都避免用复杂的中缀表达式。
无论多么复杂的表达式,转换为前缀或后缀只需要两步。
1. 将中缀表达式转化为全括号式;
2. 将所有的操作符移动到子表达式所在的左括号(前缀)或右括号(后缀)处,再删除所有括号。
中缀转后缀
在中缀表达式转换为后缀表达式的处理过程中,操作符碧操作数要晚输出,所以在扫描到对应的第二个操作数之前,需要把操作符先保存起来。
而这些暂存的操作符由于优先级的规则还有可能要反转次序输出。
( 在 A + B * C 中,+先出现,但要等 * 处理结束才能处理)
这种反转特性使得我们考虑用栈来保存战士未处理的操作符。
当遇到 ( A + B )* C ,对应的后缀形式是 AB + C * ,所以遇到左括号要标记下来,其后操作符的优先级提升了,一旦遇到右括号,就可以马上输出这个操作符。
后面的算法描述中,约定中缀表达式是有空格隔开的一系列单词(token)构成,操作符单词包括( ) * / + - 。
流程 :
1. 首先,创造空栈 opstack 用于暂存操作符,空表 postfixlist 用于保存后缀表达式。
如 :A + B * C = split => [ 'A' , '+' , 'B' , ' * ' , 'C' ]
2. 从左到右扫描中缀表达式单词列表:
如果单词是操作数,则直接添加到后缀表达式列表的末尾;
如果单词是左括号 “ ( ” ,则压入 opstack 栈顶;
如果单词是右括号 “ ) ” ,则反复弹出 opstack 栈顶操作符,加入到输出列表末尾,直到碰到左括号;
如果单词是操作符,则压入 opstack 栈顶( 但在压入之前,要比较其于栈顶操作符的优先级);
3. 扫描结束,把 opstack 剩余操作符依次弹出,添加输出列表末尾;
4. 把输出列表再用 join 方法合并后缀表达式字符串。
代码实现。
def infixToPostfix(infixexpr):
opstack = Stack()
postfixlist = []
tokenlist = map(str, infixexpr)
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:
opstack.push(token)
while not opstack.isEmpty():
postfixlist.append(opstack.pop())
print(postfixlist)
postfixlist = list(i for i in map(str, postfixlist) if i != ' ')
return ''.join(postfixlist)
print(infixToPostfix('(A+B )*C'))
后缀表达式求值
流程 :
1. 创建空栈 operandstack 用于暂存操作数。
2. 将后缀表达式用 split 方法解析为单词(token)列表。
3. 从左到右扫描单词列表。
(如果是操作数,转化为 int )
(如果是操作符,开始求值,从栈弹出两个操作数,计算后压入栈顶)
4. 单词列表扫描结束后,表达式的值就在栈顶。
5. 弹出栈顶的值。
代码实现。
def doMath(token, operand1, operand2):
if token == '+':
return operand1 + operand2
elif token == '-':
return operand1 - operand2
elif token == '*':
return operand1 * operand2
else:
return operand1 / operand2
def postfixEval(postfixExpr):
operandstack = Stack()
tokenlist = postfixExpr.split()
for token in tokenlist:
if token in "0123456789":
operandstack.push(int(token))
else:
operand2 = operandstack.pop()
operand1 = operandstack.pop()
result = doMath(token, operand1, operand2)
operandstack.push(result)
return operandstack.pop()
print(postfixEval('4 5 + 6 *'))