一本正經的聊資料結構(3) 棧和佇列

2022-03-17 18:26:39 字數 4152 閱讀 5486

前文傳送門:

「一本正經的聊資料結構(1):時間複雜度」

「一本正經的聊資料結構(2):陣列與向量」

前一篇內容我們介紹了陣列和向量,雖然說向量是陣列的乙個公升級版,但是在另乙個維度上,他們都屬於線性結構。

那麼什麼是線性結構呢?

線性結構是乙個有序資料元素的集合。常用的線性結構有:線性表,棧,佇列,雙佇列,陣列,串。

線性結構是最常用的資料結構,它最大的特點是資料元素之間存在一對一的線性關係。

線性結構擁有兩種不同的儲存結構,即順序儲存結構和鏈式儲存結構。

順序儲存的線性表稱為順序表,順序表中的儲存元素是連續的。

鏈式儲存的線性表稱為鍊錶,鍊錶中的儲存元素不一定是連續的,元素節點中存放資料元素以及相鄰元素的位址資訊。

線性結構中存在兩種操作受限的使用場景,就是我們本文要介紹的棧和佇列。

至於為什麼說棧和佇列是受限的線型結構,我們下面細聊。

棧是一種比較奇葩的資料結構,棧的結構是支援物件的插入和刪除操作,但是,棧操作的範圍僅限於棧的某一特定端,就是下面這樣的。

棧遵循先進後出( last-in-first-out, lifo )的規律,這是重點。

棧一般使用兩種方式來實現:

順序表:採用順序儲存結構可以模擬棧儲存資料的特點,從而實現棧儲存結構。

鍊錶:採用鏈式儲存結構實現棧結構。

注意,這兩種實現方式的區別,僅限於資料元素在實際物理空間上存放的相對位置,順序棧底層採用的是陣列,鏈棧底層採用的是鍊錶。

棧結構我們還是會經常用到,乙個非常經典的場景就是在瀏覽器的後退功能中。

例如我們每次開啟乙個頁面,瀏覽器都會把這個頁面放入棧中,當我們點選後退按鈕的時候,在從棧中將這個頁面取出來。

順序棧,是用順序表實現棧儲存結構。

棧儲存結構運算元據元素必須遵守 「先進後出 lifo 」 的原則。

順序表的底層是使用陣列來實現的,簡單理解可以直接理解成陣列。

只是棧結構對資料的訪問過程有特殊的限制,而陣列是沒有的。

鏈棧,是用鍊錶實現棧儲存結構。

鍊錶的結構相比較陣列而言就稍微有些複雜了,鍊錶的每個節點由兩部分組成,乙個是存放資料的,叫資料域,另乙個是存放指標的,叫指標域。

陣列在記憶體中是連續的,所以我們可以輕鬆的知道陣列的每乙個元素的位置,而鍊錶在記憶體中是分散的,我們需要乙個指標來指明下乙個元素在**。

這裡介紹的其實是最簡單的一種鍊錶,叫單鏈表,顧名思義,除了單鏈表之外還有雙鏈表,這個我們有機會後面再聊。

那麼鏈棧是將鍊錶的頭部作為棧頂,尾部作為棧底。

將鍊錶頭部作為棧頂的一端,可以避免在實現資料 「入棧」 和 「出棧」 操作時做大量遍歷鍊錶的耗時操作。

鍊錶的頭部作為棧頂,意味著:

因此,鏈棧實際上就是乙個只能採用頭插法插入或刪除資料的鍊錶。

在 python 中,棧並不是乙個基礎資料結構,不過我們可以通過**來簡單的實現它。

因為棧是可以通過兩種方式來實現,一種是順序表,另一種是鍊錶:

首先是最簡單的通過順序表來實現棧,這裡使用的是 python 中的 list 列表:

class stack(object):

def __init__(self):

'''建立空列表實現棧

'''self.__list =

def is_empty(self):

'''判斷是否為空

:return:

'''return self.__list ==

def push(self,item):

'''壓棧,新增元素

:param item:

:return:

'''def pop(self):

'''彈出棧,將元素取出

:return:

'''if self.is_empty():

return

else:

return self.__list.pop()

如果不想使用順序表來實現,還可以使用鍊錶,這裡使用的是單鏈表,鍊錶的結構需要先提前定義:

class node(object):

'''節點實現

'''def __init__(self,elem):

self.elem = elem

self.next = none

class stack(object):

def __init__(self):

'''初始化煉表頭

'''self.__head = none

def is_empty(self):

return self.__head is none

def push(self, item):

'''壓棧

:param item:

:return:

'''node = node(item)

node.next = self.__head

self.__head = node

def pop(self):

'''彈出棧

:return:

'''if self.is_empty():

return

else:

p = self.__head

self.__head = p.next

return p.elem

在鍊錶的實現中,我這裡先定義了鍊錶的資料結構,然後才定義了棧。

上面兩段**都非常簡單,只實現了最簡單的兩個功能,入棧和出棧,感興趣的同學可以自己動手實現下。

與棧一樣,佇列( queue) 也是存放資料物件的一種容器,其中的資料物件也按線性的邏輯次序排列。

佇列和棧不一樣的地方在於棧是先進後出,而佇列是先進先出( first-in-first-out, fifo )。

同棧一樣的是佇列也有兩種實現方式:

在 python 的標準庫中,python 為我們提供了執行緒安全的佇列 queue (總算不用我再自己寫個佇列了),使用方法異常簡單:

先進先出佇列 (fifo) :

import queue

q1 = queue.queue(maxsize=5)

for i in range(5):

q1.put(i)

while not q1.empty():

print('q1:',q1.get())

# 結果輸出

q1: 0

q1: 1

q1: 2

q1: 3

q1: 4

queue 這個標準庫中,還為我們提供了 lifo 佇列,即先進後出佇列,和我們前面介紹的棧非常類似,翻了下原始碼,看到是使用 list 實現的,和我們上面的實現基本一致,使用方式如下:

import queue

q2 = queue.lifoqueue(maxsize=5)

for i in range(5):

q2.put(i)

while not q2.empty():

print('q2:',q2.get())

# 結果輸出

q2: 4

q2: 3

q2: 2

q2: 1

q2: 0

本篇內容就這樣了,涉及到的**肯定會上傳**倉庫,有興趣的同學可以去翻翻看。

示例**-github

示例**-gitee

一本正經的聊資料結構(4) 樹

前文傳送門 一本正經的聊資料結構 1 時間複雜度 一本正經的聊資料結構 2 陣列與向量 一本正經的聊資料結構 3 棧和佇列 在前面的文章中,我們已經陸陸續續的介紹了一些資料結構。根據這些資料結構的實現方式,大體上可以分成兩類 基於陣列的實現和基於鍊錶的實現。這兩種實現方式各有優缺點,說不上誰一定好誰...

一本正經的說kafka的結構

kafka 從字面意思,可以看出來就是 ka f ka 是乙個有序的 檔案 訊息佇列進什麼出什麼 kafka 從logo上可以看到 他是乙個分布式的結構 乙個大節點 管理幾個小節點 乙個 zookeeper 管理 和 多個 broker 程序節點 多台機器 乙個 topic 和 多個 partiti...

資料結構 3 棧和佇列

棧和佇列也算是 資料型別。以為都是在首位操作,棧和佇列 克服了 線性表新增刪除需要移動大量元素的弱點。棧僅在尾部進行插入和刪除,尾部叫做棧頂,表頭叫做棧底。後進先出。last in first out lifo 空棧。插入叫入棧,刪除元素叫出棧。順序棧,的順序儲存結構是利用一組 位址連續的儲存單元,...