目录
1 栈概览
2 使用栈
2.1 栈接口
2.2 初始化一个栈
2.3 示例应用程序:匹配括号
3 栈的3种应用
3.1 后缀表达式
3.1.1 计算算数表达式
3.1.2 计算后缀表达式
3.1.3 将中缀表达式转换为后缀表达式
3.2 回溯算法
3.3 内存管理
4 栈的实现
4.1 测试驱动程序
4.2 将栈添加到集合层级中
4.3 数组实现
4.4 链表实现
4.5 AbstractStack类的作用
4.6 两种实现的时间和空间分析
5 案例学习:计算后缀表达式
5.1 要求
5.2 分析
5.3 设计
5.4 实现
6 小结
栈方法 |
作用 |
s.isEmpty() | 如果为空返回True,否则返回False |
__len__(s) | 和len(s)相同,返回s中的项的数目 |
__str__(s) | 和str(s)相同,返回s的字符串表示 |
s.__iter__() | 和iter(s)或for item in s:相同;从底部像顶部,访问s中的每一项 |
s.__contains__(item) | 和item in s相同,如果item在s中,返回True,否则返回False |
s1.__add__(s2) | 和s1+s2相同,返回一个新的栈,其中包含了s1和s2中的项 |
s.__eq__(anyObject) | 和s==anyObject相同,如果s等于anyObject,返回True,否则返回False。如果在对应位置的项都是相同的,这两个栈就是相等的 |
s.clear() | 将s清空 |
s.peek() | 返回s顶部的项。先验条件:s不能为空,如果栈为空的话,将会抛出一个KeyError |
s.push(item) | 在s的顶部添加一项 |
s.pop() | 在s的顶部删除一项并返回该项。先验条件:s不能为空。如果栈为空的话,将会抛出一个KeyError |
操作 | 该操作之后栈的状态 | 返回值 | 说明 |
s = |
初始化,栈为空 | ||
s.push(a) | a | 栈只包含一个项a | |
s.push(b) | a b | b是栈顶 | |
s.push(c) | a b c | c是栈顶 |
|
s.isEmpty() | a b c | False | 这个栈不为空 |
len(s) | a b c | 3 | 栈中包含3个项 |
s.peek() | a b c | c | 返回栈顶的值,但并不删除它 |
s.pop() | a b | c | 删除并返回栈顶的值,b现在成为栈顶 |
s.pop() | a | b | 删除并返回栈顶的值,a现在成为栈顶 |
s.pop() | a | 删除并返回栈顶的值 | |
s.isEmpty() | True | 栈现在为空 | |
s.peek() | KeyError | 查看一个空的栈会导致一个异常 | |
s.pop() | KeyError | 弹出一个空的栈会导致一个异常 |
|
s.push(d) | d | d是栈顶 |
s1 = ArrayStack()
s2 = LinkedStack([20, 40, 60])
示例表达式 | 状态 | 原因 |
(...)...(...) | 匹配 | |
(...)...(... | 不匹配 | 末尾漏掉了一个) |
)...(...(...) | 不匹配 | 最开头的结束),没有一个匹配的开始(; 第2个开始的(,没有对应的结束圆括号 |
[...(...)...] | 匹配 | |
[...(...]...) | 不匹配 | 方括号的部分没有正确地嵌套 |
用栈检查一个表达式的步骤如下
# -*- encoding: utf-8 -*-
# Author: ZFT
"""
Check expressions for matching brackets
"""
from Data_structure.Chapter7.linkedstack import LinkedStack
def bracketBalance1(exp):
"""exp is a string that represents the expression."""
stk = LinkedStack() # Create a new stack
for ch in exp: # Scan across the expression
if ch in ['[', '(']: # Push an opening bracket
stk.push(ch)
elif ch in [']', ')']: # Process a closing bracket
if stk.isEmpty(): # Not balanced
return False
chFromStack = stk.pop()
# Brackets must be of same type and match up
if ch == ']' and chFromStack != '[' or \
ch == ')' and chFromStack != '(':
return False
return stk.isEmpty() # They all matched up
def bracketBalance2(exp, startBracketList = ['(', '['],endBracketList = [')',']'] ):
"""exp is a string that represents the expression.
startBracketList is the list of start bracket list.
endBracketList is the list of end bracket list.
precondition:startBracketList must have the same length of endBracketList.
raise: Exception if startBracketList don't have the same length of endBracketList.
"""
if len(startBracketList) != len(endBracketList):
raise Exception("The startBracketList must have the same length with the endBracketList.")
stk = LinkedStack()
for ch in exp:
if ch in startBracketList:
stk.push(ch)
elif ch in endBracketList:
if stk.isEmpty():
return False
chFromStack = stk.pop()
if chFromStack != startBracketList[endBracketList.index(ch)]:
return False
return stk.isEmpty()
def main():
exp = input("Enter a bracketed expression:")
if bracketBalance1(exp):
print ("OK")
else:
print("Not OK")
if __name__ == "__main__":
main()
中缀形式 | 后缀形式 | 值 |
34 | 34 | 34 |
34 + 22 | 34 22 + | 56 |
34 + 22 * 2 | 34 22 2 * + | 78 |
34 * 22 + 2 | 34 22 * 2 + | 750 |
(34 + 22)* 2 | 34 22 + 2 * | 112 |
# token 指的是一个运算数或一个运算符
Create a new stack
While there are more tokens in the expression
Get the next token
If the token is an operand
Push the operand onto the stack
Else if the token is an operator
Pop the top two operands from the stack
Apply the operator to the two operands just popped
Push the resulting value onto the stack
Return the value at the top of the stack
计算一个后缀表达式的过程
后缀表达式: 4 5 6 * + 3 - 结果值:31
后缀表达式目前扫描到的部分 运算数栈 说明 还没有扫描到标记。栈为空 4 4 将运算数4压入栈 4 5 4 5 将运算数5压入栈 4 5 6 4 5 6 将运算数6压入栈 4 5 6 * 4 30 用栈顶的两个运算数的乘积来替换 4 5 6 * + 34 用栈顶的两个运算数的和来替换 4 5 6 * + 3 34 3 将运算数3压入栈 4 5 6 * + 3 - 31 用栈顶的两个运算数的差来替换 弹出最终的结果一个中缀表达式转换为后缀表达式的过程
中缀表达式:4 + 5 * 6 - 3 后缀表达式:4 5 6 * + 3
当前扫描到的中缀表达式
的位置
运算符栈 后缀表达式 说明 还没有看到标记,堆栈和后缀表达式都是空的 4 4 将4添加到后缀表达式 4 + + 4 将+压入运算符栈 4 + 5 + 4 5 将5添加到后缀表达式 4 + 5 * + * 4 5 将*压入运算符栈 4 + 5 * 6 + * 4 5 6 将6添加到后缀表达式 4 + 5 * 6 - - 4 5 6 * + 将*和+弹出栈,并将它们添加到后缀表达式,并将-压入运算符栈 4 + 5 * 6 - 3 - 4 5 6 * + 3 将3添加到后缀表达式 4 + 5 * 6 - 3 4 5 6 * + 3 - 将剩下的运算符从栈中弹出,并将其添加到后缀表达式从中缀表达式到后缀表达式的转换过程(带括号)
中缀表达式:(4 + 5) *(6 - 3) 后缀表达式:4 5 + 6 3 - *
当前扫描到的中缀表达式
的位置
运算符栈 后缀表达式 说明 还没有看到标记,堆栈和后缀表达式都是空的 ( ( 将(压入运算符栈 (4 ( 4 将4添加到后缀表达式 (4 + ( + 4 将+压入运算符栈 (4 + 5 ( + 4 5 将5添加到后缀表达式 (4 + 5) 4 5 + 弹出栈直到遇到(,并且将运算符添加到后缀表达式 (4 + 5)* * 4 5 + 将*压入运算符栈 (4 + 5) *( *( 4 5 + 将(压入运算符栈 (4 + 5) *(6 *( 4 5 + 6 将6添加到后缀表达式 (4 + 5) *(6 - *( - 4 5 + 6 将-压入运算符栈 (4 + 5) *(6 - 3 *( - 4 5 + 6 3 将3添加到后缀表达式 (4 + 5) *(6 - 3) * 4 5 + 6 3 - 弹出栈直到遇到(,并且将运算符添加到后缀表达式 (4 + 5) *(6 - 3) 4 5 + 6 3 - * 将剩下的运算符从栈中弹出,并将其添加到后缀表达式Create an empty stack
Push the starting state onto the stack
While the stack is not empty
Pop the stack and examine the state
If the state represents an ending state
Return SUCCESSFUL CONCLUSION
Else if the state has not been visited previously
Mark the state as visited
Push onto the stack all unvisited adjacent states
Return UNSUCCESSFUL CONCLUSION
# -*- encoding: utf-8 -*-
# Author: ZFT
from Data_structure.Chapter7.arraystack import ArrayStack
from Data_structure.Chapter7.linkedstack import LinkedStack
def test(stackType):
# Test an implementation with the same code.
s = stackType()
print("Length:", len(s))
print("Empty:",s.isEmpty())
print("Push 1-10")
for i in range(10):
s.push(i + 1)
print("Peeking:", s.peek())
print("Items(bottom to top):", s)
print("Length:", len(s))
print("Empty:", s.isEmpty())
theClone = stackType(s)
print("Items in clone(bottom to top)", theClone)
theClone.clear()
print("Length of clone after clear:",len(theClone))
print("Push 11")
s.push(11)
print("Popping items(top to bottom):", end = " ")
while not s.isEmpty():
print(s.pop(), end = " ")
print("\nLength:", len(s))
print("Empty:", s.isEmpty())
def main():
test(LinkedStack)
if __name__ == '__main__':
main()
# -*- encoding: utf-8 -*-
# Author: ZFT
from Data_structure.Chapter4.arrays import Array
from Data_structure.Chapter7.abstractstack import AbstractStack
class ArrayStack(AbstractStack):
"""An array-based stack implementation."""
DEFAULT_CAPACITY = 10 # For all array stacks
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which includes the
contents of sourceCollection, if it's present.
"""
self._items = Array(ArrayStack.DEFAULT_CAPACITY)
AbstractStack.__init__(self, sourceCollection)
# Accessors
def __iter__(self):
"""Supports iteration over a view of self.
Visits items from bottom to top of stack.
"""
cursor = 0
while cursor < len(self._items):
yield self._items[cursor]
cursor += 1
def peek(self):
"""Returns the item at top of the stack.
Precondition: the stack is not empty.
Raises KeyError if the stack is empty.
"""
if self.isEmpty():
raise KeyError("The stack is Empty.")
return self._items[len(self._items) - 1]
# Mutator
def clear(self):
"""Makes self become empty."""
self._size = 0
self._items = Array(ArrayStack.DEFAULT_CAPACITY)
def push(self, item):
"""Inserts item at top of the stack."""
# Resize array size here if necessary
self._items[len(self._items)] = item
self._size += 1
def pop(self):
"""Removes and returns the item at top of the stack.
Precondition: the stack is empty.
Raises KeyError if the stack is empty.
PostCondition: the top item is removed from the stack.
"""
if self.isEmpty():
raise KeyError("The stack is Empty.")
oldItem = self._items[len(self._items) - 1]
self._size -= 1
# Resize the array size here if necessary
return oldItem
# -*- encoding: utf-8 -*-
# Author: ZFT
from Data_structure.Chapter4.node import Node
from Data_structure.Chapter7.abstractstack import AbstractStack
class LinkedStack(AbstractStack):
"""Link-based stack implementation."""
def __init__(self, sourceCollecion = None):
self._items = None
AbstractStack.__init__(self, sourceCollecion)
# Accessors
def __iter__(self):
"""Supports iteration over a view of self.
Visits items from bottom to top of stack."""
def visitNodes(node):
if not node is None:
visitNodes(node.next)
tempList.append(node.data)
tempList = list()
visitNodes(self._items)
return iter(tempList)
def peek(self):
"""Returns the item at top of the stack."""
if self.isEmpty():
raise KeyError("The stack is empty.")
return self._items.data
# Mutator
def clear(self):
"""Makes self become empty."""
self._items = None
self._size = 0
def push(self, item):
"""Inserts item at top of the stack."""
self._items = Node(item, self._items)
self._size += 1
def pop(self):
"""Removes and returns the item at top of the stack.
Precondition: the stack is empty.
Raises KeyError if the stack is empty.
PostCondition: the top item is removed from the stack."""
if self.isEmpty():
raise KeyError("The stack is empty.")
oldItem = self._items.data
self._items = self._items.next
self._size -= 1
return oldItem
# -*- encoding: utf-8 -*-
# Author: ZFT
from Data_structure.Chapter7.abstractcollection import AbstractCollection
class AbstractStack(AbstractCollection):
"""An abstract stack implementation."""
def __init__(self, sourceCollection = None):
"""Sets the initial state of self, which incudes the
contents of sourceCollection, if it's present."""
AbstractCollection.__init__(self, sourceCollection)
# Mutator
def add(self, item):
"""Add item to self."""
self.push(item)
PFEvaluatorView()
Create and saves a reference to the model.
run()
while True:
Retrieve the expressions string from keyboard.
Send it to the model for formatting and print the format string.
Send it to the model for evaluation.
Either print the value or catch exceptions raised by the evaluator.
ask the model for the associated details, and display error.
messages.
format( expressionStr ):
Instantiate a scanner on the expression string.
Build a response string by iterating across the scanner and appending a
string representation of each token to the response string.
Return the response string.
evaluate( expressionStr ):
Ask the evaluator to evaluate the expression string.
Return the value.
evaluationStatus():
Ask the evaluator for its status.
Return the status
PFEvaluator( scanner )
Intialize expressionSoFar
Instantiate an ArrayStack
Save a reference to the scanner
evaluate()
Iterate across the scanner and evaluate the expression.
Raise exception in the following situation:
The scanner is None or empty
There are too many operands
There are too few operands
There are unrecognizable tokens.
A divide by 0 exception is raised by the PVM
evaluationStatus()
Return a multipart string that contains the portion of the expression
processed and the contents of the stack.
Scanner( sourceStr ):
Save a reference to the string that will be scanned and tokenized
hasNext()
Return True if the string contains another token and False otherwise.
next()
Return the next token. Raise an exception if hasnext() return False.
UNKNOWN = 0 #unknow
INT = 4 #interger
MINUS = 5 #minus operator
PLUS = 6 #plus operator
MUL = 7 #multiply operator
DIV = 8 #divide operator
Token( vlaue ):
Construct a new integer token with the specified value
Token(ch):
if ch is an operator( + - * / ), then construct a new operator token;
otherwise, construct a token of unknown type.
getType()
return a token's type
getValue()
return a token's value.
isOperator():
Return True if the token is an operator, and False Otherwise
__str__():
Return the token's numeric value as a string if the token is an
integer; otherwise, return the token's character representation.
# -*- encoding: utf-8 -*-
# Author: ZFT
"""
Tokens for processing expressions.
"""
class Token(object):
UNKNOWN = 0 # unknown
INT = 4 # integer
MINUS = 5 # minus operator
PLUS = 6 # plus operator
MUL = 7 # multiply operator
DIV = 8 # divide operator
FIRST_OP = 5 # first operator code
def __init__(self, value):
if type(value) == int:
self._type = Token.INT
else:
self._type = self._makeType(value)
self._value = value
def isOperator(self):
return self._type >= Token.FIRST_OP
def __str__(self):
return str(self._value)
def getType(self):
return self._type
def getValue(self):
return self._value
def _makeType(self, ch):
if ch == '*':
return Token.MINUS
elif ch == '+':
return Token.PLUS
elif ch == '-':
return Token.MINUS
elif ch == '/':
return Token.DIV
else:
return Token.UNKNOWN
# -*- encoding: utf-8 -*-
# Author: ZFT
"""
Defines PEEvaluatorModel and PEEvaluator
"""
from Data_structure.Chapter7.PEEvaluatorModel.tokens import Token
from Data_structure.Chapter7.PEEvaluatorModel.scanner import Scanner
from Data_structure.Chapter7.arraystack import ArrayStack
class PEEvaluatorModel(object):
def evaluate(self, sourceStr):
self._evaluator = PEEvaluator(Scanner(sourceStr))
value = self._evaluator.evaluate()
return value
def format(self, sourceStr):
normalizedStr = ""
scanner = Scanner(sourceStr)
while scanner.hasNext():
normalizedStr += str(scanner.next()) + " "
return normalizedStr
def evaluationStatus(self):
return str(self._evaluator)
class PEEvaluator(object):
def __init__(self, scanner):
self._expressionSoFar = " "
self._operandStack = ArrayStack()
self._scanner = scanner
def evaluate(self):
while self._scanner.hasNext():
currentToken = self._scanner.next()
self._expressionSoFar += str(currentToken) + " "
if currentToken.getType() == Token.INT:
self._operandStack.push(currentToken)
elif currentToken.isOperator():
if len(self._operandStack) < 2:
raise AttributeError("Too few operands on the stack.")
t2 = self._operandStack.pop()
t1 = self._operandStack.pop()
result = Token(self._computeValue(currentToken, t1.getValue(), t2.getValue()))
self._operandStack.push(result)
else:
raise AttributeError("Unknown token type.")
if len(self._operandStack) > 1:
raise AttributeError("Too many operands on the stack.")
result = self._operandStack.pop()
return result.getValue()
def __str__(self):
result = "\n"
if self._expressionSoFar == "":
result += "Portion of expression processed: none\n"
else:
result += "Portion of expression processed: "+ self._expressionSoFar + "\n"
if self._operandStack.isEmpty():
result += "The stack is empty."
else:
result += "Operands on the stack: " + str(self._operandStack)
return result
def _computerValue(self, op, value1, value2):
result = 0
theType = op.getType()
if theType == Token.PLUS:
result = value1 + value2
elif theType == Token.MINUS:
result = value1 - value2
elif theType == Token.MUL:
result = value1 * value2
elif theType == Token.DIV:
result = value1 / value2
else:
raise AttributeError("Unknown operator")
return result