【数据结构与算法Python版学习笔记】基本数据结构——栈 stack

定义

  • 一个项的有序集合

  • 添加项和移除项都发生在同一“端”

  • 分为栈顶和栈底

  • LIFO 先进后出

举例

  • 浏览器后退
  • word undo

抽象数据类型

栈的操作如下:

  • Stack() 创建一个新的空栈。它不需要参数,并返回一个空栈。

  • Push(item) 将新项添加到堆栈的顶部。它需要参数 item 并且没有返回值。

  • pop() 从栈顶删除项目。它不需要参数,返回 item。栈被修改。

  • peek() 返回栈顶的项,不删除它。它不需要参数。堆栈不被修改。

  • isEmpty() 测试看栈是否为空。它不需要参数,返回一个布尔值。

  • size() 返回栈的项目数。它不需要参数,返回一个整数。

#实现stack
class Stack:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def push(self, item):  # 将item加入栈顶,无返回值
        return 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)

s=Stack()#创建一个空栈,不包含任何数据项
print(s.isEmpty())
s.push(4)
s.push('dog')
print(s.peek())
print(s.size())

应用

简单括号匹配

  • 简单括号匹配 ()
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 += 1
    if balanced and s.isEmpty():
        return True
    else:
        return False

if __name__ == "__main__":
    print(parChecker("((()))"))
    print(parChecker("(()"))
    print(parChecker("(()())"))
    print(parChecker("(()()"))
  • 通用括号匹配{[()]}
def parChecker(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 martches(top,symbol):
                    balanced = False
        index += 1
    if balanced and s.isEmpty():
        return True
    else:
        return False

def martches(open,close):
    opens="([{"
    closers=")]}"
    return opens.index(open)==closers.index(close)

if __name__ == "__main__":
    print(parChecker("{{([][])}()}"))
    print(parChecker("[{()]"))

进制转换

  • 十进制转二进制

    def divideBy2(decNumber):
        remstack=Stack()
        while decNumber>0:
            remstack.push(decNumber%2)
            decNumber//=2
    
        binString=""
        while not remstack.isEmpty():
            binString+=str(remstack.pop())
    
        return binString
    
    if __name__ == "__main__":
        print(divideBy2(42))
    
  • 十进制转十六进制以下任意进制

    def baseConverter(decNumber,base):
        digits="0123456789ABCDEF"
        remstack=Stack()
        while decNumber>0:
            remstack.push(decNumber%base)
            decNumber//=base
    
        binString=""
        while not remstack.isEmpty():
            binString+=digits[remstack.pop()]
    
        return binString
    
    if __name__ == "__main__":
        print(baseConverter(42,16))
        print(baseConverter(255,16))
    

表达式转换

  • 中辍表达式

    • 优先级
    • 全括号中辍表达式
  • 前缀表达式

  • 后缀表达式

image

image

通用中缀转后缀算法

  • 步骤

    • 创建空栈opstack用于暂存操作符,空表postfixList用于保存后缀表达式
    • 将中缀表达式转换为单词(token)列表
    • 从左到右扫描中缀表达式单词列表
      • 若单词是操作符,则直接添加到后辍表达式列表末尾
      • 若单词是“(”,则压入opstack栈顶
      • 若单词是“)”,则反复弹出opstack栈顶操作符,加入到输出列表末尾,直到碰到左括号
      • 若单词是操作符“*/+-”,则压入opstack栈顶
        • 压入前要比较其与栈顶操作符的优先级
        • 如果栈顶比较高,则反复弹出栈顶操作符,加入到输出列表末尾
        • 知道栈顶操作符优先级低于它
    • 扫描结束后,把opstack栈中的所有剩余操作符一次弹出,添加到输出列表末尾
    • 把输出列表用join方法合并成后缀表达式字符串,算法结束
  • 示例图

    image

  • 代码

def infixToPostfix(infixexpr):
    prec={}
    prec["*"]=3
    prec["/"]=3
    prec["+"]=2
    prec["-"]=2
    prec["("]=1
    opStack=Stack()
    postfixList=[]
    tokenList=infixexpr.split()
    #return tokenList

    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)

if __name__ == "__main__":
    print(infixToPostfix("( A * B ) + ( C * D )"))
    print(infixToPostfix("( ( A + B ) * ( C + D ) )"))
    print(infixToPostfix("( A + B * C + D )"))

后缀表达式求值

  • 步骤
    • 创建空栈operandStack用于暂存操作数
    • 将后缀表达式用split方法解析为单词(token)的列表
    • 从左到右扫描单词列表
      • 若单词是一个操作数,将单词转换为整数int,压入operandStack栈顶
      • 若单词是一个操作符(*/+-),就开始求职,从栈顶弹出2个操作数,先弹出的是右操作数,后弹出的是左操作数,计算后将值重新压入栈顶
    • 单词列表扫描结束后,表达式的值就在栈顶
    • 弹出栈顶的值,返回

image

  • 代码
def postfixEval(postfixExpr):
    operandStack=Stack()
    tokenList=postfixExpr.split()
    print(tokenList) 

    for token in tokenList:
        if token in "0123456789":
            operandStack.push(int(token))
        else:
            operand1=operandStack.pop()
            operand2=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
    elif op=="-":
        return op1-op2

if __name__ == "__main__":
    print(postfixEval("7 8 + 9 1 + *"))
  • 改进
import operator
def postfixEval(postfixExpr):
    operandStack=Stack()
    tokenList=postfixExpr.split()
    print(tokenList) 

    operators={
        '*':operator.mul,
        '/':operator.truediv,
        '+':operator.add,
        '-':operator.sub,
    }

    for token in tokenList:
        if token in "0123456789":
            operandStack.push(int(token))
        else:
            operand1=operandStack.pop()
            operand2=operandStack.pop()
            result =operators[token](operand1,operand2)
            operandStack.push(result)
            
    return operandStack.pop()

if __name__ == "__main__":
    print(postfixEval("7 8 + 9 1 + *"))
posted @ 2021-04-22 13:08  砥才人  阅读(168)  评论(0编辑  收藏  举报