Python数据结构-stack(堆栈)

堆栈(英语:stack)又称为栈或堆叠,是计算机科学中一种特殊的串列形式的抽象数据类型,其特殊之处在于只能允许在链表或数组的一端进行加入数据(英语:push)和输出数据(英语:pop)的运算。由于堆栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO, Last In First Out)的原理运作。 来自维基百科

抽象数据描述如下:

ADT Stack:
    Stack(self)     # 创建空栈
    is_empty(self)  # 判断栈是否为空
    push(self, elem)    # 将元素elem加入栈
    pop(self)       # 删除栈中最后加入的元素并将其返回
    top(self)           # 取得栈中最后压入的元素,不删除

栈大多的实现是采用线性表

顺序表栈实现

  1. 定义一个异常类
class StackUnderflow(ValueError): # 栈下溢(空栈访问)
    pass
  1. Python 的 list 是线性表的一种实现,在此使用 list 作为栈元素存储区,整体实现如下:
class SStack:
    def __init__(self):
        self._elems = [] # 使用list存储栈元素

    def is_empty(self):
        return self._elems == []

    def push(self, elem):
        self._elems.append(elem)

    def pop(self):
        if self._elems == []:
            raise StackUnderflow("in SStack.pop()")
        return self._elems.pop()

    def top(self):
        if self._elems == []:
            raise StackUnderflow("in SStack.top()")
        return self._elems[-1]

  1. 简单的书写测试用例

if __name__ == '__main__':
    s = SStack()
    assert s.is_empty() is True
    try:
        s.pop()
    except StackUnderflow:
        print("StackUnderflow")
    s.push(123)
    assert s.is_empty() is not True
    assert s.pop() == 123

简单应用:括号匹配问题

给定一个字符串,其中的字符只包含三种括号:花括号{ }、中括号[ ]、圆括号( ),即它仅由( ) [ ] { }这六个字符组成。
设计算法,判断该字符串是否有效,即字符串中括号是否匹配。括号匹配要求括号必须以正确的顺序配对,如{ [ ] ( ) }[ ( { } [ ] ) ]等为正确的格式,而[ ( ] ){ [ ( ) }( { } ] )均为不正确的格式。

完整的括号匹配算法流程如下:

  1. 从前向后扫描字符串,遇到无关字符则跳过;
  2. 遇到左括号 x,就把 x 压栈;
  3. 遇到右括号 y:
    • 如果发现栈顶元素x和该括号y匹配,则栈顶元素出栈,继续判断下一个字符;
    • 如果栈顶元素x和该括号y不匹配,字符串不匹配;
    • 如果栈为空,字符串不匹配;
  4. 扫描完成后,如果栈恰好为空,则字符串匹配,否则,字符串不匹配。

代码如下:


def check_parens(text):
    stack = SStack()
    left_parens = "([{"
    right_parens = ")]}"
    parens = {")":"(", "]":"[", "}":"{"}
    for i in text:
        if i in left_parens:
            stack.push(i)
        elif i in right_parens:
            if stack.is_empty():
                return False
            if parens[i] != stack.pop():
                return False
    if stack.is_empty():
        return True
    return False

if __name__ == '__main__':
    assert check_parens("[{1232}]") is True
    assert check_parens("[{[}]") is False
    assert check_parens("[{123444]}]") is False
    assert check_parens("][{}]") is False

栈与函数调用经典问题之简单背包问题

递归实现如下:

# 简单背包问题
def knap_rec(weight, wlist, n):
    if weight == 0:
        return True
    if weight < 0 or (weight > 0 and n < 1):
        return False
    if knap_rec(weight - wlist[n-1], wlist, n-1):
        return True
    if knap_rec(weight, wlist, n-1):
        return True
    else:
        return False

assert knap_rec(100, [90, 40, 20, 10, 50], 4) is True

栈实现如下:


# 可利用回溯法的设计思想来解决背包问题。
# 首先将 n 件物品排成一列,依次选取;若装入某件物品后,背包内物品的总质量不超过背包最大装载质量时,则装入(进栈);
# 否则放弃这件物品的选择,选择下一件物品试探,直至装入的物品总和正好是背包的最大转载质量为止。这时我们称背包装满。
# 若装入若干物品的背包没有满,而且又无其他物品可以选入背包,说明已装入背包的物品中有不合格者,需从背包中取出最后装入的物品(退栈)
# 然后在未装入的物品中挑选,重复此过程,直至装满背包(有解),或无物品可选(无解)为止。

def knapstack(weight, wlist):
    n = len(wlist)  # 可选的物品数量
    stack = SStack()  # 创建一个栈
    k = 0  # 当前所选择的物品游标
    while stack.is_empty() is not True or k < n:  # 栈不为空或者k<n
        while weight > 0 and k < n:  # 还有剩余空间并且有物品可装
            if weight >= wlist[k]:  # 剩余空间大于等于当前物品重量
                print(wlist[k])
                stack.push(k)  # 把物品装备背包
                weight -= wlist[k]  # 背包空间减少
            k += 1  # 继续向后找
        if weight == 0:  # 找到解
            print(stack._elems)
            # return True
        # 回退过程
        k = stack.pop()  # 把最后一个物品拿出来
        print(wlist[k])
        weight += wlist[k]  # 背包总容量加上w[k]
        print(weight)
        k += 1  # 装入下一个物品

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,148评论 0 13
  • 情寄悲秋心难却 醉意兰舟 木叶飘落解千愁 长相思 望相守 难分难解迷亭楼 秋风起 黄花瘦 不知吹落谁家 别离忧 浅...
    清浅佳人阅读 211评论 3 2
  • 图片发自简书App 诉衷曲 作者/田子 自:田子...
    狼烟诗影阅读 399评论 0 3
  • 在提出辞职后的第二天,我终于任性了一把,开启了一场说走就走的旅行,虽然没有及时告知父母和家人,导致了旅行前,...
    Emma梦阅读 704评论 5 3
  • 最近写感悟突然就没有思绪了,原因可能是最近太忙累,也可能是输入太少。但是还是想要继续坚持,哪怕只写这两百多字。 我...
    凌凌喵阅读 184评论 0 3