数据结构与算法(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
原文地址:https://www.cnblogs.com/yeshengCqupt/p/12571924.html