欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python數據結構之棧詳解

 更新時間:2022年03月07日 15:01:13   作者:盼小輝丶  
棧和隊列是在程序設計中常見的數據類型,從數據結構的角度來講,棧和隊列也是線性表,是操作受限的線性表。本文將詳細介紹一下Python中的棧,感興趣的可以了解一下

0. 學習目標

棧和隊列是在程序設計中常見的數據類型,從數據結構的角度來講,棧和隊列也是線性表,是操作受限的線性表,它們的基本操作是線性表操作的子集,但從數據類型的角度來講,它們與線性表又有著巨大的不同。本節(jié)將首先介紹棧的定義和其不同實現,并且給出棧的一些實際應用。

通過本節(jié)學習,應掌握以下內容:

  • 棧的基本概念及不同實現方法
  • ?;静僮鞯膶崿F及時間復雜度
  • 利用棧的基本操作實現復雜算法

1. 棧的基本概念

1.1 棧的基本概念

棧 (Stack) 是限定僅在序列一端執(zhí)行插入和刪除操作的線性表,對于棧而言,可進行操作的一端稱為棧頂 (top),而另一端稱為棧底 (bottom)。如果棧中不含任何元素則稱其為空棧。

棧提供了一種基于在集合中的時間來排序的方式,最近添加的元素靠近頂端,舊元素則靠近底端。最新添加的元素被最先移除,這種排序原則也稱為后進先出 (last in first out, LIFO) 或先進后出 (fast in last out, FILO)。

棧在現實中的例子隨處可見,如下圖所示,球桶中的球構成了一個棧,每次只能從頂部取出一個,放回時也只能置于頂部。假設棧為S = ( a0 , a1 , … , en)為棧頂元素,棧中元素按的順序入棧 (push),而棧頂元素是第一個退棧 (pop) 的元素。

通過觀察元素的添加和移除順序,就可以快速理解棧所蘊含的思想。下圖展示了棧的入棧和出棧過程,棧中元素的插入順序和移除順序恰好是相反的。

1.2 棧抽象數據類型

除了主要的操作(入棧和出棧)外,棧還具有初始化、判空和取棧頂元素等輔助操作。具體而言,棧的抽象數據類型定義如下:

基本操作:

1. __itit__(): 初始化棧

創(chuàng)建一個空棧

2. size(): 求取并返回棧中所含元素的個數 n

若棧為空,則返回整數0

3. isempty(): 判斷是否為空棧

判斷棧中是否存儲元素

4. push(data): 入棧

將元素 data 插入棧頂

5. pop(): 出棧

刪除并返回棧頂元素

4. peek(): 取棧頂元素

返回棧頂元素值,但并不刪除元素

1.3 棧的應用場景

棧具有廣泛的應用場景,例如:

  • 符號的匹配,具體描述參考第3.3小節(jié);
  • 函數調用,每個未結束調用的函數都會在函數棧中擁有一塊數據區(qū),保存了函數的重要信息,包括函數的局部變量、參數等;
  • 后綴表達式求值,計算后綴表達式只需一個用于存放數值的棧,遍歷表達式遇到數值則入棧,遇到運算符則出棧兩個數值進行計算,并將計算結果入棧,最后棧中保留的唯一值即為表達式結果;
  • 網頁瀏覽中的返回按鈕,當我們在網頁間進行跳轉時,這些網址都被存放在一個棧中;
  • 編輯器中的撤銷序列,與網頁瀏覽中的返回按鈕類似,棧保存每步的編輯操作。

除了以上應用外,我們在之后的學習中還將看到棧用作許多算法的輔助數據結構。

2. 棧的實現

和線性表一樣,棧同樣有兩種存儲表示方式。

2.1 順序棧的實現

順序棧是棧的順序存儲結構,其利用一組地址連續(xù)的存儲單元從棧底到棧頂依次存放。同時使用指針top來指示棧頂元素在順序棧中的索引,同樣順序??梢允枪潭ㄩL度和動態(tài)長度,當棧滿時,定長順序棧會拋出棧滿異常,動態(tài)順序棧則會動態(tài)申請空閑空間。

2.1.1 棧的初始化

順序棧的初始化需要三部分信息:stack 列表用于存儲數據元素,max_size 用于存儲 stack 列表的最大長度,以及 top 用于記錄棧頂元素的索引:

class Stack:
    def __init__(self, max_size=10):
        self.max_size = max_size
        self.stack = self.max_size * [None]
        self.top = -1

2.1.2 求棧長

由于 top 表示棧頂元素的索引,我們可以據此方便的計算順序棧中的數據元素數量,即棧長:

    def size(self):
        return self.top + 1

2.1.3 判???/p>

根據棧的長度可以很容易的判斷棧是否為空棧:

    def isempty(self):
        if self.size() == 0:
            return True
        else:
            return False

2.1.4 判棧滿

由于需要提前申請棧空間,因此我們需要能夠判斷棧是否還有空閑空間:

    def isfully(self):
        if self.size() == self.max_size:
            return True
        else:
            return False

2.1.5 入棧

入棧時,需要首先判斷棧中是否還有空閑空間,然后根據棧為定長順序棧或動態(tài)順序棧,入棧操作稍有不同:

[定長順序棧的入棧操作] 如果棧滿,則引發(fā)異常:

    def push(self, data):
        if self.isfully():
            raise IndexError('Stack Overflow!')
        else:
            self.top += 1
            self.stack[self.top_1] = data

[動態(tài)順序棧的入棧操作] 如果棧滿,則首先申請新空間:

    def resize(self):
        new_size = 2 * self.max_size
        new_stack = [None] * new_size
        for i in range(self.num_items):
            new_stack[i] = self.items[i]
        self.stack = new_stack
        self.max_size = new_size
    def push(self, data):
        if self.isfully():
            self.resize()
        else:
            self.top += 1
            self.stack[self.top_1] = data

入棧的時間復雜度為O(1)。這里需要注意的是,雖然當動態(tài)順序棧滿時,原棧中的元素需要首先復制到新棧中,然后添加新元素,但根據《順序表及其操作實現》中順序表追加操作的介紹,由于n次入棧操作的總時間T(n) 與O(n) 成正比,因此入棧的攤銷時間復雜度仍可以認為是O(1)。

2.1.6 出棧

若棧不空,則刪除并返回棧頂元素:

    def pop(self):
        if self.isempty():
            raise IndexError('Stack Underflow!')
        else:
            result = self.stack[self.top]
            self.top -= 1
            return result

2.1.7 求棧頂元素

若棧不空,則只需返回棧頂元素:

    def peek(self):
        if self.isempty():
            raise IndexError('Stack Underflow!')
        else:
            return self.stack[self.top]

2.2 鏈棧的實現

棧的另一種存儲表示方式是使用鏈式存儲結構,因此也常稱為鏈棧,其中 push 操作是通過在鏈表頭部插入元素來實現的,pop 操作是通過從頭部刪除節(jié)點來實現的。

2.2.1 棧結點

棧的結點實現與鏈表并無差別:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
    def __str__(self):
        return str(self.data)

2.2.2 棧的初始化

棧的初始化函數中,使棧頂指針指向 None,并初始化棧長:

class Stack:
    def __init__(self):
        self.top = None
        # 棧中元素數
        self.length = 0

2.2.3 求棧長

返回 length 的值用于求取棧的長度,如果沒有 length 屬性,則需要遍歷整個鏈表才能得到棧長:

    def size(self):
        return self.length

2.2.4 判棧空

根據棧的長度可以很容易的判斷棧是否為空棧:

    def isempty(self):
        if self.length == 0:
            return True
        else:
            return False

2.2.5 入棧

入棧時,在棧頂插入新元素即可:

    def push(self, data):
        p = Node(data)
        p.next = self.top
        self.top = p
        self.length += 1

由于插入元素是在鏈表頭部進行的,因此入棧的時間復雜度為O(1),在這種情況下鏈尾作為棧底 。

2.2.6 出棧

若棧不空,則刪除并返回棧頂元素:

    def pop(self):
        if self.isempty():
            raise IndexError("Stack Underflow!")
        ele = self.top.data
        self.top = self.top.next
        self.length -= 1
        return ele

由于刪除元素僅需修改頭指針指向其 next 域,因此出棧的時間復雜度同樣為O(1)。

2.2.7 求棧頂元素

若棧不空,返回棧頂元素即可,但棧頂元素并不會被刪除:

    def peek(self):
        if self.isempty():
            raise IndexError("Stack Underflow!")
        return self.top.data

2.3 棧的不同實現對比

本節(jié)我們將對比棧的不同實現之間的異同:

順序棧

  • 操作的時間復雜度均為O(1),列表的尾部作為棧頂
  • 棧滿時需要進行動態(tài)的擴展,復制原棧元素到新棧中

鏈棧

  • 操作的時間復雜度均為O(1),鏈表的頭部作為棧頂
  • 優(yōu)雅的擴展,無需考慮棧滿,需要額外的空間存儲指針

3. 棧應用

接下來,我們首先測試上述實現的鏈表,以驗證操作的有效性,然后利用實現的基本操作來解決實際算法問題。

3.1 順序棧的應用

首先初始化一個順序棧 stack,然后測試相關操作:

# 初始化一個最大長度為4的棧
s = Stack(4)
print('???', s.isempty())
for i in range(4):
    print('入棧元素:', i)
    s.push(i)
print('棧滿?', s.isfully())
print('棧頂元素:', s.peek())
print('棧長度為:', s.size())
while not s.isempty():
    print('出棧元素:', s.pop())

測試程序輸出結果如下:

??? True
入棧元素: 0
入棧元素: 1
入棧元素: 2
入棧元素: 3
棧滿? True
棧頂元素: 3
棧長度為: 4
出棧元素: 3
出棧元素: 2
出棧元素: 1
出棧元素: 0

3.2 鏈棧的應用

首先初始化一個鏈棧 stack,然后測試相關操作:

# 初始化新棧
s = Stack()
print('???', s.isempty())
for i in range(4):
    print('入棧元素:', i)
    s.push(i)
print('棧頂元素:', s.peek())
print('棧長度為:', s.size())
while not s.isempty():
    print('出棧元素:', s.pop())

測試程序輸出結果如下:

??? True
入棧元素: 0
入棧元素: 1
入棧元素: 2
入棧元素: 3
棧頂元素: 3
棧長度為: 4
出棧元素: 3
出棧元素: 2
出棧元素: 1
出棧元素: 0

3.3 利用?;静僮鲗崿F復雜算法

匹配符號是指正確地匹配左右對應的符號(符號允許進行嵌套),不僅每一個左符號都有一個右符號與之對應,而且兩個符號的類型也是一致的,下標展示了一些符號串的匹配情況:

符號串是否匹配
[]()()匹配
[(())()不匹配
{([]())}匹配
(())[]}不匹配

為了檢查符號串的匹配情況,需要遍歷符號串,如果字符是 (、[ 或 { 之類的開始分隔符,則將其寫入棧中;當遇到諸如 )、] 或 } 等結束分隔符時,則棧頂元素出棧,并將其與當前遍歷元素進行比較,如果它們匹配,則繼續(xù)解析符號串,否則表示不匹配。當遍歷完成后,如果棧不為空,則同樣表示不匹配:

def isvalid_expression(expression):
    stack = Stack()
    symbols = {')':'(', ']':'[', '}':'{'}
    for s in expression:
        if s in symbols:
            if stack:
                top_element = stack.pop()
            else:
                top_element = '#'
            if symbols[s] != top_element:
                return False
        else:
            stack.push(s)
    return not stack

由于我們只需要遍歷符號串一邊,因此算法的時間復雜度為O(n),算法的空間復雜度同樣為O(n)。

給定一鏈表(帶有頭結點) L : L0→L1→…→Ln ,將其重排為:L0→Ln→L1→Ln−1 … 。

例如鏈表中包含 9 個元素,則下圖現實了重排前后的鏈表元素情況:

由于棧的先進后出原則,可以利用棧與原鏈表的配合進行重排,首次按遍歷鏈表,將每個結點入棧;棧中元素的出棧順序為原鏈表結點的逆序,然后交替遍歷鏈表和棧,構建新鏈表。

def reorder_list(L):
    p = L.head.next
    if p == None:
        return L
    stack = Stack()
    while p!= None:
        stack.push(p)
        p = p.next
    l = L.head.next
    from_head = L.head.next
    from_stack = True
    while (from_stack and l != stack.peek() or (not from_stack and l != from_head)):
        if from_stack:
            from_head = from_head.next
            l.next = stack.pop()
            from_stack = False
        else:
            l.next = from_head
            from_stack = True
        l = l.next
    l.next = None

該算法的時間復雜度和空間復雜度均為O(n)。

以上就是Python數據結構之棧詳解的詳細內容,更多關于Python 棧的資料請關注腳本之家其它相關文章!

相關文章

  • 詳解基于Transformer實現電影評論星級分類任務

    詳解基于Transformer實現電影評論星級分類任務

    這篇文章主要為大家介紹了詳解基于Transformer實現電影評論星級分類任務過程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Python文件操作實戰(zhàn)案例之用戶登錄

    Python文件操作實戰(zhàn)案例之用戶登錄

    以前只是用c語言文件操作打過用戶登入,學了幾天的python我感覺我又行了,下面這篇文章主要給大家介紹了關于Python文件操作實戰(zhàn)案例之用戶登錄的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-05-05
  • python中wx模塊的具體使用方法

    python中wx模塊的具體使用方法

    這篇文章主要介紹了python中wx模塊的具體使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • Vue中自定義指令的三個常用方法小結

    Vue中自定義指令的三個常用方法小結

    這篇文章主要為大家詳細介紹了Vue中自定義指令的三個常用方法,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以了解一下
    2024-02-02
  • python使用數字與字符串方法技巧

    python使用數字與字符串方法技巧

    這篇文章主要介紹了python使用數字與字符串方法技巧,文章內容介紹詳細具有一的參考價值,需要的小伙伴可以參考一下
    2022-03-03
  • django之用戶、用戶組及權限設置方式

    django之用戶、用戶組及權限設置方式

    這篇文章主要介紹了django之用戶、用戶組及權限設置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • pytorch中 gpu與gpu、gpu與cpu 在load時相互轉化操作

    pytorch中 gpu與gpu、gpu與cpu 在load時相互轉化操作

    這篇文章主要介紹了pytorch模型載入之gpu和cpu互轉操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • Python實現APP自動化發(fā)微信群消息的示例代碼

    Python實現APP自動化發(fā)微信群消息的示例代碼

    本文主要介紹了Python實現APP自動化發(fā)微信群消息的示例代,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下碼
    2022-01-01
  • windows安裝TensorFlow和Keras遇到的問題及其解決方法

    windows安裝TensorFlow和Keras遇到的問題及其解決方法

    這篇文章主要介紹了windows安裝TensorFlow和Keras遇到的問題及其解決方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-07-07
  • Python實現兩款計算器功能示例

    Python實現兩款計算器功能示例

    這篇文章主要為大家詳細介紹了Python實現兩款計算器功能示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12

最新評論