栈抽象数据类型及Python实现

目录

栈的实现

栈的应用

        十进制转化为二进制

        中缀转后缀

        后缀表达式求值


栈的实现

栈Stack:一种有次序的数据项集合,在栈中,数据项的加入和移除都仅发生在同一端。

一端叫栈 “ 顶top ” ,另一端叫栈 “ 底base ”。

栈的特性:反转次序。

在栈中数据,通常称为 “ 先进后出 ” 或 “ 后进先出 (Last in First out)” 。

如:浏览器后退键,先退出最新访问的网页。代码的撤销键,先撤销最近输入代码。

抽象数据类型Stack

“ 栈 ”(Stack)是一个有次序的数据集,每个数据项仅从 “ 栈顶 ” 加入数据集中。

“ 栈 ”的定义操作:

Stack() : 创建一个空栈,不包含任何数据项。

push(item) : 将item加入栈顶,无返回值。

pop() : 将栈顶数据移除,并返回栈被修改。

peek() : 查看栈顶数据,返回栈顶数据,不修改栈。

isEmpty() : 返回栈是否为空栈。

size() : 返回栈中有多少个数据项。

用python实现  ADT Stack

步骤:

        1 . 将 ADT Stack 实现为 python 的 Class 。

        2 . 将 ADT Stack 的操作实现成 Class 的方法。

        3 . 因为 Stack 是一个数据集,我们选用最常见的数据集 List 实现。

           (可以将 List 任意一端(index=0或1)设置为栈顶)

 实现代码。

class Stack:
    def __init__(self):  # 创建一个空栈
        self.items = []

    def isEmpty(self):  # 返回栈是否为空
        return self.items == []

    def push(self, item):  # 将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)

测试代码。

def main():
    s = Stack()
    print(s.isEmpty())
    s.push(1)
    s.push(2)
    s.push('jiang')
    print(s.isEmpty())
    print(s.peek())
    s.size()
    print(s.pop())
    print(s.pop())
    print(s.pop())
    print(s.size())

栈的应用

        十进制转化为二进制

所谓 “ 进制 ” 就是用多少个字符来表示整数。

十进制就是 0 ~ 9 这是个数字字符表示,二进制就是0,1两个字符表示。

十进制转化为二进制采用 “ 除以2 求余数” 的算法。

流程 :

 除二的过程,得到的余数是从低到高的顺序,但输出测试从高到低,所以使用栈。

 代码实现。

def divideBy2(decnumber):
    remstack = Stack()

    while decnumber > 0:
        rem = decnumber % 2
        remstack.push(rem)
        decnumber = decnumber // 2

    binstring = ""

    while not remstack.isEmpty():
        binstring = binstring + str(remstack.pop())

    return binstring

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

例:十进制转换为十六进制以下实现代码。

def baseCoverter(decnumber, base):
    
    digits = "0123456789ABCDEF"
    
    remstack = Stack()
    
    while decnumber > 0:
        rem = decnumber % base
        remstack.push(rem)
        decnumber = decnumber // base
    
    newstring = ""
    
    while not remstack.isEmpty():
        newstring = newstring + digits[remstack.pop()]
        
    return newstring

中缀表达法:A+B         前缀表达法:+AB         后缀表达法:AB+

中缀表达式 ( A + B ) * C  按照转换规则前缀表达式 “  +AB * C” , 后缀表达式 “ AB+C * ” 。

因为在前缀后缀表达式中,操作符的次序完全决定了运算的次序,所以在很多情况下,表达式的计算机表示都避免用复杂的中缀表达式。

 无论多么复杂的表达式,转换为前缀或后缀只需要两步。

1. 将中缀表达式转化为全括号式;

2. 将所有的操作符移动到子表达式所在的左括号(前缀)或右括号(后缀)处,再删除所有括号。

 

 

        中缀转后缀

在中缀表达式转换为后缀表达式的处理过程中,操作符碧操作数要晚输出,所以在扫描到对应的第二个操作数之前,需要把操作符先保存起来。

而这些暂存的操作符由于优先级的规则还有可能要反转次序输出。

( 在 A + B * C 中,+先出现,但要等 * 处理结束才能处理)

这种反转特性使得我们考虑用栈来保存战士未处理的操作符。

当遇到 ( A + B )* C ,对应的后缀形式是 AB + C * ,所以遇到左括号要标记下来,其后操作符的优先级提升了,一旦遇到右括号,就可以马上输出这个操作符。

后面的算法描述中,约定中缀表达式是有空格隔开的一系列单词(token)构成,操作符单词包括( ) * / + - 。

流程 :

1.  首先,创造空栈 opstack 用于暂存操作符,空表 postfixlist 用于保存后缀表达式。

        如 :A + B * C = split => [ 'A' , '+' , 'B' , ' * ' , 'C' ]

2.  从左到右扫描中缀表达式单词列表:

        如果单词是操作数,则直接添加到后缀表达式列表的末尾;

        如果单词是左括号  “ ( ”  ,则压入 opstack 栈顶;

        如果单词是右括号  “ ) ”  ,则反复弹出 opstack 栈顶操作符,加入到输出列表末尾,直到碰到左括号;

        如果单词是操作符,则压入 opstack 栈顶( 但在压入之前,要比较其于栈顶操作符的优先级);

3.  扫描结束,把 opstack 剩余操作符依次弹出,添加输出列表末尾;

4.  把输出列表再用 join 方法合并后缀表达式字符串。

代码实现。

def infixToPostfix(infixexpr):
    opstack = Stack()
    postfixlist = []
    tokenlist = map(str, infixexpr)

    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:
            opstack.push(token)

    while not opstack.isEmpty():
        postfixlist.append(opstack.pop())
        print(postfixlist)
        postfixlist = list(i for i in map(str, postfixlist) if i != ' ')
    return ''.join(postfixlist)


print(infixToPostfix('(A+B )*C'))

        后缀表达式求值

 流程 :

1.  创建空栈 operandstack 用于暂存操作数。

2.  将后缀表达式用 split 方法解析为单词(token)列表。

3.  从左到右扫描单词列表。

  (如果是操作数,转化为 int )

  (如果是操作符,开始求值,从栈弹出两个操作数,计算后压入栈顶)

4.  单词列表扫描结束后,表达式的值就在栈顶。

5.  弹出栈顶的值。

代码实现。

def doMath(token, operand1, operand2):
    if token == '+':
        return operand1 + operand2
    elif token == '-':
        return operand1 - operand2
    elif token == '*':
        return operand1 * operand2
    else:
        return operand1 / operand2


def postfixEval(postfixExpr):
    operandstack = Stack()
    tokenlist = postfixExpr.split()
    for token in tokenlist:
        if token in "0123456789":
            operandstack.push(int(token))
        else:
            operand2 = operandstack.pop()
            operand1 = operandstack.pop()
            result = doMath(token,  operand1, operand2)
            operandstack.push(result)
    return operandstack.pop()


print(postfixEval('4 5 + 6 *'))

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值