Python數(shù)據(jù)結(jié)構(gòu)-stack(堆棧)

堆棧(英語(yǔ):stack)又稱為棧或堆疊澡腾,是計(jì)算機(jī)科學(xué)中一種特殊的串列形式的抽象數(shù)據(jù)類型,其特殊之處在于只能允許在鏈表或數(shù)組的一端進(jìn)行加入數(shù)據(jù)(英語(yǔ):push)和輸出數(shù)據(jù)(英語(yǔ):pop)的運(yùn)算。由于堆棧數(shù)據(jù)結(jié)構(gòu)只允許在一端進(jìn)行操作返奉,因而按照后進(jìn)先出(LIFO, Last In First Out)的原理運(yùn)作。 來(lái)自維基百科

抽象數(shù)據(jù)描述如下:

ADT Stack:
    Stack(self)     # 創(chuàng)建空棧
    is_empty(self)  # 判斷棧是否為空
    push(self, elem)    # 將元素elem加入棧
    pop(self)       # 刪除棧中最后加入的元素并將其返回
    top(self)           # 取得棧中最后壓入的元素吗氏,不刪除

棧大多的實(shí)現(xiàn)是采用線性表

順序表?xiàng)?shí)現(xiàn)

  1. 定義一個(gè)異常類
class StackUnderflow(ValueError): # 棧下溢(空棧訪問)
    pass
  1. Python 的 list 是線性表的一種實(shí)現(xiàn)芽偏,在此使用 list 作為棧元素存儲(chǔ)區(qū),整體實(shí)現(xiàn)如下:
class SStack:
    def __init__(self):
        self._elems = [] # 使用list存儲(chǔ)棧元素

    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. 簡(jiǎn)單的書寫測(cè)試用例

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

簡(jiǎn)單應(yīng)用:括號(hào)匹配問題

給定一個(gè)字符串弦讽,其中的字符只包含三種括號(hào):花括號(hào){ }污尉、中括號(hào)[ ]、圓括號(hào)( )往产,即它僅由( ) [ ] { }這六個(gè)字符組成被碗。
設(shè)計(jì)算法,判斷該字符串是否有效仿村,即字符串中括號(hào)是否匹配锐朴。括號(hào)匹配要求括號(hào)必須以正確的順序配對(duì),如{ [ ] ( ) }[ ( { } [ ] ) ]等為正確的格式蔼囊,而[ ( ] ){ [ ( ) }( { } ] )均為不正確的格式焚志。

完整的括號(hào)匹配算法流程如下:

  1. 從前向后掃描字符串,遇到無(wú)關(guān)字符則跳過(guò)畏鼓;
  2. 遇到左括號(hào) x酱酬,就把 x 壓棧;
  3. 遇到右括號(hào) y:
    • 如果發(fā)現(xiàn)棧頂元素x和該括號(hào)y匹配云矫,則棧頂元素出棧岳悟,繼續(xù)判斷下一個(gè)字符;
    • 如果棧頂元素x和該括號(hào)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

棧與函數(shù)調(diào)用經(jīng)典問題之簡(jiǎn)單背包問題

遞歸實(shí)現(xiàn)如下:

# 簡(jiǎn)單背包問題
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

棧實(shí)現(xiàn)如下:


# 可利用回溯法的設(shè)計(jì)思想來(lái)解決背包問題。
# 首先將 n 件物品排成一列斗这,依次選榷;若裝入某件物品后表箭,背包內(nèi)物品的總質(zhì)量不超過(guò)背包最大裝載質(zhì)量時(shí)赁咙,則裝入(進(jìn)棧);
# 否則放棄這件物品的選擇免钻,選擇下一件物品試探彼水,直至裝入的物品總和正好是背包的最大轉(zhuǎn)載質(zhì)量為止。這時(shí)我們稱背包裝滿极舔。
# 若裝入若干物品的背包沒有滿凤覆,而且又無(wú)其他物品可以選入背包,說(shuō)明已裝入背包的物品中有不合格者拆魏,需從背包中取出最后裝入的物品(退棧)
# 然后在未裝入的物品中挑選盯桦,重復(fù)此過(guò)程,直至裝滿背包(有解)渤刃,或無(wú)物品可選(無(wú)解)為止拥峦。

def knapstack(weight, wlist):
    n = len(wlist)  # 可選的物品數(shù)量
    stack = SStack()  # 創(chuàng)建一個(gè)棧
    k = 0  # 當(dāng)前所選擇的物品游標(biāo)
    while stack.is_empty() is not True or k < n:  # 棧不為空或者k<n
        while weight > 0 and k < n:  # 還有剩余空間并且有物品可裝
            if weight >= wlist[k]:  # 剩余空間大于等于當(dāng)前物品重量
                print(wlist[k])
                stack.push(k)  # 把物品裝備背包
                weight -= wlist[k]  # 背包空間減少
            k += 1  # 繼續(xù)向后找
        if weight == 0:  # 找到解
            print(stack._elems)
            # return True
        # 回退過(guò)程
        k = stack.pop()  # 把最后一個(gè)物品拿出來(lái)
        print(wlist[k])
        weight += wlist[k]  # 背包總?cè)萘考由蟱[k]
        print(weight)
        k += 1  # 裝入下一個(gè)物品

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市溪掀,隨后出現(xiàn)的幾起案子事镣,更是在濱河造成了極大的恐慌,老刑警劉巖揪胃,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璃哟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡喊递,警方通過(guò)查閱死者的電腦和手機(jī)随闪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骚勘,“玉大人铐伴,你說(shuō)我怎么就攤上這事撮奏。” “怎么了当宴?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵畜吊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我户矢,道長(zhǎng)玲献,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任梯浪,我火速辦了婚禮捌年,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挂洛。我一直安慰自己礼预,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布虏劲。 她就那樣靜靜地躺著托酸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伙单。 梳的紋絲不亂的頭發(fā)上获高,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天哈肖,我揣著相機(jī)與錄音吻育,去河邊找鬼。 笑死淤井,一個(gè)胖子當(dāng)著我的面吹牛布疼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播币狠,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼游两,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了漩绵?” 一聲冷哼從身側(cè)響起贱案,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎止吐,沒想到半個(gè)月后宝踪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碍扔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年瘩燥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片不同。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡厉膀,死狀恐怖溶耘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情服鹅,我是刑警寧澤凳兵,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站企软,受9級(jí)特大地震影響留荔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜澜倦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一聚蝶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藻治,春花似錦碘勉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雏节,卻和暖如春胜嗓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背钩乍。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工辞州, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寥粹。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓变过,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親涝涤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子媚狰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容