线性结构--栈 Stack(python)

1.什么是线性结构?

  • 生活中的线性结构
    在这里插入图片描述

  • 线性结构的称呼 在这里插入图片描述

  • 不同线性结构的关键区别在于数据项增减的方式。有的结构只允许数据项从一端添加,而有的结构则允许数据项从两端移除。

  • 4个最简单但功能强大的线性结构 :栈Stack,队列Queue,双端队列Deque和列表List。

2.栈抽象数据类型及Python实现

  • 一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端.这一端叫栈“顶top”,另一端叫栈“底base”.

  • 生活中的栈(在顶部放书或者取走书)
    在这里插入图片描述

  • 次序:后进先出LIFO

    距离栈底越近的数据项,留在栈中的时间就越长;而最新加入栈的数据项会被最先移除。

  • 抽象数据类型“栈”定义为如下的操作
    1)Stack():创建一个空栈,不包含任何数据项
    2)push(item):将item加入栈顶,无返回值
    3)pop():将栈顶数据项移除,并返回,栈被修改
    4)peek():“窥视”栈顶数据项,返回栈顶的数据项但不移除,栈不被修改
    5)isEmpty():返回栈是否为空栈
    6)size():返回栈中有多少个数据项

  • 抽象数据类型Stack操作案例
    在这里插入图片描述

  • 用Python实现ADT Stack

    将ADT Stack实现为Python的一个Class;将ADT Stack的操作实现为Class的方法;由于Stack是一个数据集(结构),所以可以采用Python 的原生数据集来实现,我们选用列表 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)
  • 测试代码
from pythonds.basic.stack import Stack
s = Stack()
print(s.isEmpty())
s.push(4)
s.push('dog')
print(s.peek())
s.push(True)
print(s.size())
print(s.isEmpty())
s.push(8.4)
print(s.pop())
print(s.pop())
print(s.size())
  • 运行结果
True
dog
3
False
8.4
True
2
  • 实现方法二

在这里插入图片描述

  • 栈顶首端的版本(左),其 push/pop(insert(0,item)、pop(0))的复杂度为O(n)
  • 栈顶尾端的实现 (右),其push/pop(append(item)、pop())的复杂度为O(1)
    在这里插入图片描述

3. 栈的应用:简单括号匹配

  • 括号的使用必须遵循 “平衡”规则:
    首先,每个开括号要恰好对应一个闭括号;其次,每对开闭括号要正确的嵌套:
    在这里插入图片描述
  • 构造括号匹配识别算法
    从左到右扫描括号串,最后打开的左括号,应该匹配最先遇到的右括号;这样,第一个左括号(最早打开),就应该匹配最后一个右括号(最后遇到)。 这种次序反转的识别,正好符合栈的特性。
    在这里插入图片描述
  • 流程图
    在这里插入图片描述
  • 代码
from pythonds.basic.stack import Stack
def parChecker(symbolString):
    s = Stack()
    index = 0
    balanced = True
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if (symbol == '('):
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                s.pop()
        index = index + 1
    if s.isEmpty() and balanced:
        return True
    else:
        return False


print(parChecker("((()))"))
print(parChecker("(()"))
  • 更多括号的匹配

    在实际的应用里,我们会碰到更多种括号
    如python中列表所用的方括号“[]”
    字典所用的花括号“{}”
    元组和表达式所用的圆括号“()”
    List item

  • 代码

from pythonds.basic.stack import Stack
def parChecker(symbolString):
    s = Stack()
    index = 0
    balanced = True
    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 matches(top, symbol):
                    balanced = False
        index = index + 1
    if s.isEmpty() and balanced:
        return True
    else:
        return False
def matches(open, close):
    if '({['.index(open) == ')}]'.index(close):
        return True
    else:
        return False
print(parChecker("((([])))"))

4.十进制转化为二进制

  • 二进制是计算机原理中最基本的概念,作为组成 计算机最基本部件的逻辑门电路,其输入和输出均仅为两种状态:0和1

    十进制是0~9这十个数字字符

  • 十进制数除以2 的余数从高位到低位写出来就是二进制数
    在这里插入图片描述

  • 除以2”的过程,得到的余数是从低到高的次序,而输出则是从高到低,所以需要一个栈来反转次序

  • 代码

from pythonds.basic.stack import Stack
def divideBy2(decNumber):
    remstack = Stack()
    while decNumber > 0:
        rem = decNumber % 2
        remstack.push(rem)
        decNumber = decNumber // 2  # //代表整数除法
    symbol = ''
    while not remstack.isEmpty():
        symbol = symbol + str(remstack.pop())
    return symbol
print(divideBy2(42))

  • 十进制转化为二进制的方法扩展到更多进制同样适用
    List item
  • 十进制转化为16进制以下任意代码
def baseConverter(decNumber,base):
    digits = '0123456789ABCDEF'
    remstack = Stack()
    while decNumber>0:
        rem = decNumber%base
        remstack.push(rem)
        decNumber = decNumber // base # //代表整数除法
    symbol = ''
    while not remstack.isEmpty():
        symbol = symbol+digits[remstack.pop()]
    return symbol

5.表达式转换

常见表达式:

  • 中缀表达式:B+C
  • 前缀表达式:+BC
  • 后缀表达式:BC+

表达式转换

  • 符号和两个操作数连在一起时,他们是一起执行的,比如*BC,则B乘以C是在一起的
    在这里插入图片描述
    在这里插入图片描述

中缀转后缀算法

  • 在这里插入图片描述

  • 代码

def infixToPostfix(infixexpr):
    prec = {}
    prec['/'] = 3
    prec['*'] = 3
    prec['+'] = 2
    prec['-'] = 2
    prec['('] = 1

    optStack = Stack()
    postfixList = []
    tokenList = infixexpr.split()

    for token in tokenList:
        if token in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' or token in '0123456789':
            postfixList.append(token)
        elif token == '(':
            optStack.push(token)
        elif token == ')':
            top = optStack.pop()
            while top != '(':
                postfixList.append(token)
                top = optStack.pop()
        else:
            while not optStack.isEmpty() and prec[optStack.peek()] >= prec[token]:
                postfixList.append(optStack.pop())
            optStack.push(token)
    while not optStack.isEmpty():
        postfixList.append(optStack.pop())

    return "".join(postfixList)


infixToPostfix("A * B + C * D")

6.后缀表达式求值

  • List item

  • 代码

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

    for token in tokenList:
        if token in '0123456789':
            optStack.push(int(token))
        else:
            num2 = optStack.pop()
            num1 = optStack.pop()
            res = doMath(token, num1, num2)
            optStack.push(res)

    return optStack.pop()


def doMath(opt, num1, num2):
    if opt == '*':
        return num1 * num2
    elif opt == '/':
        return num1 / num2
    elif opt == '+':
        return num1 + num2
    else:
        return num1 - num2


postfixEval("7 8 + 3 2 + /")
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铃音.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值