基本数据结构:栈

根据《Python数据结构和算法分析》和其他网络资料整理而成。


什么是栈?

栈是有序集合,添加操作和移除操作发生在同一端。

栈里面的元素离底端越近,代表在栈中的时间越长,因此栈的底端具有非常重要的意义。新添加的元素将被最先删除。这种排序原则是LIFO(last-in first out),后进先出

例如书本的堆叠

栈的抽象数据类型

栈的抽象数据类型由下面的结构和操作定义。

  • Stack() 创建一个空栈。不需要参数,返回一个空栈。
  • push(item) 将一个元素添加到栈的顶端。需要一个参数item,且无返回值
  • pop() 将顶端的元素删除。不需要参数,但是有返回值。
  • peek() 返回栈顶端的元素。不要参数,也不修改栈的内容。
  • isEmpty()检查栈是否为空。不需要参数,返回一个布尔值。
  • size()返回栈中元素的数目。不需要参数,返回一个整数。

用python实现栈

明确定义栈的抽象数据类型后,我们用Python来实现。抽象数据类型的实现被称为数据结构。

因为栈是元素的集合,所以可以使用Python提供的列表实现。

实现方式一

用列表的头部作为栈的底端,利用pop()和append()方法。

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)

实现方式二

利用列表的尾部作为栈的底端,所以pop()和append()这组不再使用。应当使用pop(0)和insert(0,item)访问下标为0,也就是第一个元素。

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

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

    def push(self,item):
        self.items.insert(0,item)

    def pop(self):
        self.items.pop(0)

    def peek(self):
        return self.items[0]

    def size(self):
        return len(self.items)

上述两种实现都可行,但是二者在性能方面肯定是有差异。append和pop()方法的时间复杂度都是O(1),这意味着不论栈中有多少元素,第一种实现中的push和pop都会在恒定的时间内完成。第二种实现的性能受限于栈中的个数,因为insert(0)和pop(0)的时间复杂度是O(n),元素越多时间越慢。

匹配符号

匹配括号

匹配括号是每一个左括号都有与之对应的一个右括号,并且括号对有正确的嵌套关系。下面是正确匹配的括号串。

(()()())

(((())))

下面是不匹配的括号串

((()

((())

我们编写一个算法,它从左到右读取一个括号串,然后判断其中的括号是否匹配。为了解决这个问题,需要注意到一个很重要的现象。。当从左到右处理括号时,最右边的无匹配左括号 必须与接下来遇到的第一个右括号相匹配。并且,在第一个位置的左括号可能要 等到处理至最后一个位置的右括号时才能完成匹配。相匹配的右括号与左括号出现的顺序相反。 这一规律暗示着能够运用栈来解决括号匹配问题

一旦认识到用栈来保存括号是合理的,算法编写起来就会十分容易。由一个空栈开始,从左 往右依次处理括号。如果遇到左括号,便通过 push 操作将其加入栈中,以此表示稍后需要有一 个与之匹配的右括号。反之,如果遇到右括号,就调用 pop 操作。只要栈中的所有左括号都能 遇到与之匹配的右括号,那么整个括号串就是匹配的;如果栈中有任何一个左括号找不到与之匹 配的右括号,则括号串就是不匹配的。在处理完匹配的括号串之后,栈应该是空的。

# 括号匹配
def parChecker(symbolString):
    s = Stack()
    balanced = True
    index = 0
    while index < len(symbolString) and balanced:
        symbol = symbolString[index]
        if symbol == "(":
            s.push(symbol)
        else:
            if s.isEmpty():
                balanced = False
            else:
                s.pop()
        index += 1
    if balanced and s.isEmpty():
        return True
    else:
        return False

匹配符号

对于匹配括号的升级,例如:

[[(‘’)]]

[{)']

各类左右符号的组合,在以上的代码增加[],{}的处理即可。

# 符号匹配

def parChecker(symbolString):
    i = 1
    s = Stack()
    balanced = True
    index = 0
    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 += 1

    if balanced and s.isEmpty():
        return True
    else:
        return False

def matches(left,right):

    lefts = "([{"
    rights = ")]}"
    return lefts.index(left) == rights.index(right)

进制转换

十进制—>二进制

十进制转换的二进制的方法是不断除以二,直至商为0。然后把各余数倒序连起来,例如:

100/2 = 50…0

50/2 =25…0

25/2 = 12…1

12/2 = 6…0

6/2 = 3…0

3/2 = 1…1

1/2 = 0…1

所以最终结果为1100100

最终程序如下:

class Stack:
    def __init__(self):
        self.items = []
    def push(self,item):
        self.items.append(item)
    def pop(self):
        return self.items.pop()
    def isEmpty(self):
        return self.items == []
    def peek(self):
        return self.items[len(self.items)-1]
    def size(self):
        return len(self.items)
    def printf(self):
        print(self.items)

def divide_to_2(num):
    s = Stack()
    binStr = ""
    while num > 0:
        s.push(num % 2)
        num = num // 2
    while not s.isEmpty():
        binStr = binStr + str(s.pop())
    return binStr

num = int(input('输入数字:'))
print(divide_to_2(num))

十进制— > 任意进制

def divide_to_base(num,base):
    s = Stack()
    baseStr = ""
    while num > 0:
        s.push(num % base)
        num = num // base
    while not s.isEmpty():
        baseStr = baseStr + str(s.pop())
    return baseStr

num,base = map(int,input('输入数字和目的进制:').split())
print(divide_to_base(num,base))

Python的进制转换

考虑到语法特性,Python 对于进制转换的函数,已经做好的封装。

十进制—>其他进制
  1. 十进制—>二进制:bin(999)

  2. 十进制—>八进制:oct(999)

  3. 十进制—>二进制:hex(999)

其他进制—>十进制
  1. 二进制—>十进制:int("10",2)
  2. 八进制转十进制: int("0o13",8) (前缀可以不写)
  3. 十六进制—>十进制: int("0xaa",16) (前缀可不写)

前序、中序和后序表达式

日常使用中,我们使用的是中序表达式。

中序表达式前序表达式后序表达式
A + B+ A BA B +

下面是中缀表达式转换成其他表达式的方法:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值