数据结构与算法(python版)之栈

一、什么是栈

在这里插入图片描述

在这里插入图片描述
  抽象数据类型“栈”是一个有次序的数据集,每一个数据仅从“栈顶”一端加入到数据集中或从数据集中移除,栈具有后进先出LIFO特性。
在这里插入图片描述

二、栈的特性:反转特性

  进栈和出栈的次序正好相反。计算机操作上的栈,如浏览器的“后退back”按钮,最先back的是最近访问的网页,Word的“Undo”按钮,最先撤销的是最近的操作。
在这里插入图片描述

三、栈的6个基本操作

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

  栈的操作样例
在这里插入图片描述

四、用python实现ADT Stack

1.思路:

  (1)将ADT Stack实现为python的一个Class;
  (2)将ADT Stack的操作实现为Class的方法;
  由于Stack是一个数据集,所以可以采用python的原生数据集来实现,选用最常用的数据集List来实现。

2.实现细节:

  可以将List的任意一端(index=0或者-1)设置为栈顶。
  我们选用List的末端(index=-1)作为栈顶。这样栈的操作就可以通过对List的append和pop来实现。
在这里插入图片描述

3.代码实现:

 (1)List末端作为栈顶

class Stack:
    def __init__(self):
        self.items = []

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

    def push(self, 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)

 (2)List首端作为栈顶

class Stack:
    def __init__(self):
        self.items=[]
    def push(self,item):
        self.items.insert(0,item)
    def pop(self):
        return self.items.pop(0)
    def peek(self):
        return self.items[0]
    def isEmpty(self):
        return self.items==[]
    def size(self):
        return len(self.items)

 (2)首端和末端的区别
  ①二者的功能完全相同;
  ②在实现上,push()、pop()、peek()三个函数不同;
  ③性能不同,栈顶是List首端的版本,其push/pop的复杂度为O(n),而栈顶是List末端的版本,其push/pop的复杂度为O(1)。其主要和List的操作有关。

五、栈的应用一:括号匹配

1.括号平衡规则

  (1)每个开括号要恰好对应一个闭括号;
  (2)每对开闭括号要正确嵌套;

2.思路

  (1)从左到右扫描括号串;
  (2)最新打开的左括号,应该最先遇到右括号;
  这样,第一个左括号,应该匹配最后一个右括号,这种次序反转的识别,正好符合栈的特性。
在这里插入图片描述

3.程序流程图

在这里插入图片描述

4.实现源程序

def parChecker(symbolStr):
    s=Stack()
    index=0
    match=True
    while index<len(symbolStr) and match:
        symbol=symbolStr[index]
        if symbol=='(':
            s.push(symbol)
        else:
            if s.isEmpty():
                match=False
            else:
                s.pop()
        index=index+1
    if s.isEmpty() and match:
        return True
    else:
        return False

5.多种括号的匹配问题

 (1)需要修改的地方:
  ①各种左括号入栈;
  ②遇到右括号时,检查栈顶左括号和右括号是否属于同一类括号。
 (2)实现程序:

def parCheckerMix(symbolStr):
    s=Stack()
    index=0
    match=True
    while index<len(symbolStr) and match:
        symbol=symbolStr[index]
        if symbol in '([{':
            s.push(symbol)
        else:
            if s.isEmpty():
                match=False
            else:
                top=s.pop()
                if not isSameType(top,symbol):
                    match=False
        index=index+1
    if s.isEmpty() and match:
        return True
    else:
        return False

def isSameType(left,right):
    lefts='([{'
    rights=')]}'
    return lefts.index(left)==rights.index(right)

六、栈的应用二:十进制转换成二进制

1.方法

  十进制转换为二进制,采用的是“除以2求余数”的算法,即将整数不断除以2,每次得到的余数就是由低到高的二进制位。
在这里插入图片描述
  “除以2”的过程,得到的余数是从低到高的次序,而输出是从高到低,所以需要一个栈来反转次序。

2.实现程序

def divideBy2(decNum):
    remStack=Stack()
    while decNum>0:
        #求余
        rem=decNum%2
        remStack.push(rem)
        #整数除
        decNum=decNum//2

    binStr=''
    while not remStack.isEmpty():
        binStr=binStr+str(remStack.pop())
    return binStr

3.扩展

  十进制转换成二进制的算法可以很容易的扩展成十进制转换成N进制。只需要将“除以2求余数”改为“除以N求余数”。

  十进制转换为十六进制以下任意进制的代码:

def baseConverter(decNum,base):
    digits='0123456789ABCDEF'
    remStack=Stack()
    while decNum>0:
        #求余
        rem=decNum%base
        remStack.push(rem)
        #整数除
        decNum=decNum//base

    binStr=''
    while not remStack.isEmpty():
        binStr=binStr+digits[remStack.pop()]
    return binStr

七、栈的应用三:表达式转换

1.中缀表达式

在这里插入图片描述

2.中缀表达式的优先级

在这里插入图片描述

3.全括号中缀表达式

在这里插入图片描述

4.前缀和后缀表达式

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.中缀表达式转换为前缀和后缀表达式

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.通用的中缀转后缀表达式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

7.通用的中缀转后缀算法流程

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
示例:
在这里插入图片描述

8.通用的中缀转后缀实现程序

输入表达式字符串时,操作符和操作数用空格隔开。

def infixToPostfix(infixexpr):
    #定义操作符优先级的字典
    prec={}
    prec["*"]=3
    prec["/"]=3
    prec["+"]=2
    prec["-"]=2
    prec["("]=1
    opStack=Stack();
    postfixList=[]
    #用空格将字符串拆分
    tokenList=infixexpr.split()
    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)

print(infixToPostfix('( 4 + 3 ) * 5'))

八、栈的应用四:后缀表达式求值

1.思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.实例1:

在这里插入图片描述

3.实例2:

在这里插入图片描述

4.后缀表达式求值流程

在这里插入图片描述

5.实现程序

输入表达式字符串时,操作符和操作数用空格隔开。

def postfixEval(postfixExpr):
    operandStack=Stack()
    tokenList=postfixExpr.split()

    for token in tokenList:
        if token in "0123456789":
            operandStack.push(int(token))
        else:
            operandRight=operandStack.pop()
            operandLeft=operandStack.pop()
            result=doMath(token,operandLeft,operandRight)
            operandStack.push(result)
    return operandStack.pop()

def doMath(op,opL,opR):
    if op=='*':
        return opL*opR
    if op=='/':
        return opL/opR
    if op=='+':
        return opL+opR
    else:
        return opL-opR

print(postfixEval('2 3 + 5 * 1 -'))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值