• 数据结构与算法(6)——栈Stack


    • 基础定义

    什么是栈:栈是一种有次序的数据项集合。在栈中,数据项的加入和移除都仅仅发生在同一端,这一端叫栈顶(top),没有操作的另一端叫栈底(base)。

    特性:后进先出,先进后出

    • 栈的基本操作

    这里需要知道在python里面是没有栈的,但是我们可以模拟一个栈。

    首先我们需要定义的一些栈的基本操作:

    Stack() 创建一个空栈,不包含任何数据项
    push(item) 将item加入栈顶,无返回值
    pop() 将栈顶数据项移除,并返回,栈被修改
    peek() 查看栈顶数据项,返回栈顶数据项但不移除,且不修改栈
    isEmpty() 返回栈是否为空
    size() 返回栈中有多少个数据项

     

    这里,我们可以用list类型实现一个栈的操作:

     1 class Stack:
     2     '''
     3     自己定义的一个栈
     4     '''
     5     def __init__(self):
     6         self.items =[]
     7     def isEmpty(self):
     8         return self.items==[]
     9     def push(self,item):
    10         return self.items.append(item)
    11     def pop(self):
    12         return self.items.pop()
    13     def peek(self):
    14         return self.items[len(self.items)-1]
    15     def size(self):
    16         return len(self.items)
    17 if __name__ == '__main__':
    18     s = Stack()
    19     s.push('1')
    20     s.push('a')
    21     print(s.isEmpty())
    22     print(s.peek())
    23     print(s.size())
    1 [out]:
    2 False
    3 a
    4 2
    5 
    6 Process finished with exit code 0
    • 栈的应用
    1. 简单括号匹配

    任务:对括号左右对应匹配,构造一个括号匹配算法。从左到右扫描括号,最新打开的左括号,应该匹配最先遇到的右括号 

    流程图:

     代码:

     1 from Stack import Stack
     2 def parChecker(symbolString):
     3     s = Stack()
     4     balanced = True
     5     index = 0
     6     while index < len(symbolString) and balanced:
     7         symbol = symbolString[index]
     8         if symbol == "(":
     9             s.push(symbol)
    10         else:
    11             if s.isEmpty():
    12                 balanced = False
    13             else:
    14                 s.pop()
    15         index = index + 1
    16     if balanced and s.isEmpty():
    17         return True
    18     else:
    19         return False
    20 print(parChecker('((()))))'))
    21 print(parChecker('(((())))'))
    [OUT]:
    1
    False 2 True 3 4 Process finished with exit code 0

    但是在实际应用中,括号往往比较复杂,比如{}()[]:

    代码:

     1 from Stack import Stack
     2 def parChecker2(symbolString):
     3     s = Stack()
     4     balanced = True
     5     index = 0
     6     while index < len(symbolString) and balanced:
     7         symbol = symbolString[index]
     8         if symbol in "({[":
     9             s.push(symbol)
    10         else:
    11             if s.isEmpty():
    12                 balanced = False
    13             else:
    14                 top = s.pop()
    15                 if not matches(top,symbol):
    16                     balanced = False
    17         index = index + 1
    18     if balanced and s.isEmpty():
    19         return True
    20     else:
    21         return False
    22 def matches(open,close):
    23     opens = '({['
    24     closers = ')}]'
    25     return opens.index(open) == closers.index(close) #匹配open和close在opens和closers中的位置索引是否相等
    26 print(parChecker2('{{([][])}()}'))
    27 print(parChecker2('[{()}'))
    [out]
    E:ProgramsPythonPython38python.exe "F:/yesheng/DATA/code/data struct/parchecker.py"
    True
    False
    
    Process finished with exit code 0

    参考:https://www.bilibili.com/video/BV1QJ411w7bB?p=17

             2. 进制转换

    1)十进制转换为二进制:除2取余

     1 from Stack import Stack
     2 
     3 def divideBy2(decNumber):
     4     '''
     5     次序反转
     6     :param decNumber: 十进制
     7     :return: 二进制
     8     '''
     9     remstack = Stack()
    10 
    11     while decNumber > 0:
    12         rem = decNumber % 2 #余数
    13         remstack.push(rem)
    14         decNumber = decNumber // 2 #整除数
    15 
    16     binString = ""
    17     while not remstack.isEmpty():
    18         binString = binString + str(remstack.pop())
    19     return binString
    20 print(divideBy2(42))
    [out]
    E:ProgramsPythonPython38python.exe "F:/yesheng/DATA/code/data struct/jinzhi.py"
    101010
    
    Process finished with exit code 0

    2)十进制转换为任意进制

     1 def baseConverter(decNumber,base):
     2     '''
     3     十进制转换为十六以下任意进制
     4     :param decNumber:十进制
     5     :param base:目标N进制
     6     :return:转换结果
     7     '''
     8     digits = '0123456789ABCDEF'
     9 
    10     remstack = Stack()
    11     while decNumber > 0:
    12         rem = decNumber % base
    13         remstack.push(rem)
    14         decNumber = decNumber // base
    15     newString = ''
    16     while not remstack.isEmpty():
    17         newString = newString + digits[remstack.pop()]
    18     return newString
    19 print(baseConverter(25,2))
    20 print(baseConverter(25,16))
    [OUT]
    E:ProgramsPythonPython38python.exe "F:/yesheng/DATA/code/data struct/jinzhi.py" 11001 19 Process finished with exit code 0

             3.  表达式转换

     对于一些全括号表达式,移动操作符后和得到前缀和后缀表达式。

    前缀和后缀表达式,操作符的次序决定运算的次序,离操作符近的先做,远的后做。

     看第一个,A+B*C+D,对于前缀表达式,首先与操作符最近的是*BC,所以,先做BC乘法,第二近的是+A,所以紧接着做A+B*C,最后是A+B*C+D,后缀表达式以此类推。

    因此,将中缀表达式转换为前缀表达式和后缀表达式的思路是:先将中缀表达式转化为全括号的形式,然后将所有的操作符移动到子表达式所在的左括号(前缀)或者右括号(后缀)处,先替代括号,然后删除所有括号。

     这里介绍下通用的中缀表达式转后缀表达式算法:

    在从左到右扫描逐个字符扫描中缀表达式的过程中,用一个Stack来暂时保存未处理的操作符,此时,栈顶的操作符就是最近暂存进去的,当遇到一个新的操作符,就需要跟栈顶的操作符比较下优先级,再进行处理。

    例如:

    ( A * B ) + ( C * D )
     1 from Stack import Stack
     2 
     3 def infixTOPostfix(infixexpr):
     4     prec = {}
     5     #记录操作符的优先级
     6     prec['*'] = 3
     7     prec['/'] = 3
     8     prec['+'] = 2
     9     prec['-'] = 2
    10     prec['('] = 1
    11     opStack = Stack()
    12     postfixList = []
    13     tokenList = infixexpr.split() #将表达式转换成list
    14 
    15     for token in tokenList:
    16         if token in 'ABCDEFGHIJKLIMOPQRSTUVWXYZ' or token in '0123456789':
    17             postfixList.append(token) #元素直接保存
    18         elif token == '(':
    19             opStack.push(token)
    20         elif token ==')':
    21             topToken = opStack.pop()
    22             while topToken != '(':
    23                 postfixList.append(topToken)
    24                 topToken = opStack.pop()
    25         else:
    26             while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]):
    27                 postfixList.append(opStack.pop())
    28             opStack.push(token)
    29     while not opStack.isEmpty():
    30         postfixList.append(opStack.pop())
    31     return ''.join(postfixList)
    32 s = "( A * B ) + ( C * D )"
    33 print(infixTOPostfix(s))
    [out]
    
    AB*CD*+
    Process finished with exit code 0

             4. 后缀表达式求值

    问题:在对后缀表达式从左至右扫描过程中,由于操作符在操作数后面,因此要求后缀表达式形式的值,需要先暂存操作数,然后在碰到操作符的时候,再将暂存的操作数结合操作符进行实际计算。(仍然是栈的特性:操作符只作用于离它最近的两个操作数,最后入栈的最先计算)。

    例子:4 5 6 * +

    算法流程:先将 4 入栈,再将5入栈,接着将6入栈,然后将5 6 出栈进行乘法操作,将结果入栈,然后再将栈里面栈顶以及栈顶后面的元素做加法得到结果。

    代码:

     1 from Stack import Stack
     2 
     3 def postfixEval(postfixExpr):
     4     operandStack = Stack()
     5     tokenList = postfixExpr.split()
     6 
     7     for token in tokenList:
     8         if token in '0123456789':
     9             operandStack.push(int(token))
    10         else:
    11             operand2 = operandStack.pop()
    12             operand1 = operandStack.pop()
    13             result = doMath(token,operand1,operand2)
    14             operandStack.push(result)
    15     return operandStack.pop()
    16 def doMath(op, op1, op2):
    17     if op == '*':
    18         return op1 * op2
    19     elif op == '/':
    20         return op1 / op2
    21     elif op == '+':
    22         return op1 + op2
    23     elif op == '-':
    24         return op1 - op2
    25 print(postfixEval('4 5 6 * +'))
    [OUT]
    
    34
    
    Process finished with exit code 0
  • 相关阅读:
    FLASH置于底层
    图片等比缩放
    fedora 系统使用 Broadcom BCM4312 无线网卡(转)
    ubuntu语言问题
    轻松安装、卸载Linux软件
    redhat6.0下使用vnc
    http网络安装centos 5.5系统总结
    如何在windows下搭建python的IDE开发环境
    对做技术的一点思考
    C++继承类和基类之间成员函数和虚函数调用机制
  • 原文地址:https://www.cnblogs.com/yeshengCqupt/p/12571924.html
Copyright © 2020-2023  润新知