c 資料結構佇列棧屍體 資料結構與演算法 棧與佇列

2021-10-13 18:35:41 字數 2823 閱讀 7033

使用抽象資料型別可以幫助我們更好的理解資料所需的操作,之後再進行具體的資料型別實現。實際上,往往是操作影響著我們決定資料型別該如何實現,這裡有兩種典型的資料結構-棧和佇列。

1、棧首先,普通的線性表實現是有兩個埠可以訪問的,但是如果作為棧就要封閉一端,只能訪問另一端。這當然不是自討苦吃,棧是一種抽象資料結構,是對現實世界物件的模擬。比如,自助餐廳中的一疊盤子,新盤子放在這一疊盤子的最上面,取得時候也是從最上面取。將其抽象出來就是棧,這是最合適的抽象方式。

基於棧的操作非常簡單:

棧的實現不是難點,基於棧的操作也很簡單,重點是棧的運用。

動態圖:

棧的先進後出規則,本質上代表著資料的次序,常見的二叉樹先序、中序、後序非遞迴遍歷,其實就是借用這種規則實現的。想要深入理解棧,沒有取巧的方法,見多識廣用在這裡再合適不過了,這裡使用乙個簡單的例子來加深對棧的理解。

大整數加法,現在有個需求,將1856845129568452684和8948756841235879相加,怎麼處理?這兩個整數太大了,尋常的整數型別根本無法儲存他們,更別說他們相加的結果。為了解決這個問題,可以將這種非常大的數看成一串數字,分別存到兩個棧中,然後從棧中彈出數,進行加法操作。

偽**如下:

簡單起見,這裡給出456和7891相加時棧的結構:

這不就是我們學過的加法計算公式嘛,是的,這裡使用棧模擬了加法過程。

將數字壓入棧中,其實維持了千位、百位、十位、個位之間的次序,正是這個原因才能保證棧彈出的時候數字相加是合理的。這只是棧簡單的一種運用,在現實生活中,所有需要保持次序的資料,都可以使用棧這種先進後出的結構,通過巧妙的設計完成演算法邏輯。

2、佇列

佇列是一種簡單的等待序列,在尾部加入元素時佇列加長,在前端刪除資料時佇列縮短。與棧不同,佇列是一種使用兩端的結構:一端用來加入新元素,另一端用來刪除元素。佇列是先進先出的結構。

佇列的操作與棧操作相似:

動態圖:

佇列的實現:

佇列的一種可能實現方式是使用陣列,但這並非最佳選擇。元素從隊尾加入而從隊首刪除,這會釋放陣列中的某些單元,這些單元不應該浪費。一種可能的做法是使用迴圈陣列,如果隊尾已滿而隊首有空的單元,可以將新加元素放入隊首,形成迴圈陣列,這種做法是空間比較緊張時的無奈之舉,因為它破壞了佇列的簡單易用性,所以不推薦。

佇列的另一種可能實現是使用雙向鍊錶,那麼執行入佇列和出佇列操作僅需要常數時間,並且沒有陣列實現中空間的浪費,因此,推薦這種方法。

佇列的變種:

在許多情況下,簡單的佇列結構是不夠的,先入先出機制需要使用某些優先規則來完善。在郵政局中,殘疾人應該比其他人享有一定的優先權。在程序佇列中,由於系統的功能需求,即使在等待佇列中程序p1在p2之前,p2也需要在p1之前執行。以此類推,需要一種修正的佇列,這就是所謂的優先佇列。

優先佇列可以用兩種鍊錶的變種實現。一種變種是所有的元素按照進入順序排序,出隊時按照優先順序。另一種是根據元素的優先順序決定新增元素的位置。在這兩種情況下,總的執行時間都是o(n),在標準庫中使用後一種方式實現的,因為我們希望在元素出隊時可以盡可能的快。

顧名思義,雙端佇列就是可以在佇列的兩端壓入、彈出元素。這就有問題了,雙端佇列和普通的陣列、鍊錶有什麼區別?不都可以兩端訪問嘛。當然是有區別的,雙端佇列的產生是基於以下需求的。眾所周知,陣列和鍊錶是線性表的兩種實現方式,陣列的優勢在於可以常數時間內隨機訪問元素,鍊錶的優勢在於可以常數時間內在兩端插入資料。那麼,有沒有一種實現方式可以綜合這兩個特點呢?答案是雙端佇列。

一切的奧妙在於雙端佇列的實現方式。首先從陣列講起,我們定義了陣列a,陣列a本身是支援常數時間內隨機訪問元素的,但是如果在頭部插入資料,就會造成大量元素後移,這是不能容忍的。怎麼解決呢?那就再定義乙個陣列b,如果在a頭部插入新元素a,就將a放到陣列b的尾端,這時候陣列a和陣列b都是被封裝在雙端佇列中的,並且雙端佇列維護了一段鏈式結構,其中每個節點指向乙個陣列。看到這裡想必大家已經明白,雙端佇列通過維護多個陣列來避免頭部插入操作造成的大量資料後移,儘管雙端佇列的實現比較複雜,但是作為使用者,既可以常數時間內隨機訪問元素,又可以常數時間內在佇列兩端插入資料,這對於某些場景下非常合適。

雙端佇列並不能取代陣列和鍊錶,因為陣列和鍊錶的實現簡單、直觀,可以滿足大部分需求,只有在特殊場景下才去考慮雙端佇列,這就是所謂的對症下藥。

3、標準庫實現

這裡簡單介紹下標準庫中的棧和佇列。

在標準庫中棧和佇列是一種容器介面卡。什麼叫做容器介面卡呢?其實就是拿一種已有的容器,在上面重新封裝對外暴漏的介面,拼裝成一種新的特殊容器。

標準庫首先實現了雙端佇列,它是一種真正的容器,不是容器介面卡。

標準庫中的棧是一種容器介面卡,預設是基於雙端佇列實現的,我們在使用過程中可以指定新的底層容器,比如向量或者鍊錶。

標準庫中的佇列也是一種容器介面卡,預設也是基於雙端佇列實現的,但是我們只能選擇鍊錶作為新的底層容器,不能選擇向量。這是因為佇列是允許在頭部刪除資料的,而向量沒有實現這種操作。

標準庫中的優先佇列也是一種容器介面卡,預設是基於向量實現的,但是我們也能選擇使用雙端佇列作為底層容器。注意,這裡不能選擇鍊錶,因為標準庫中的優先佇列要求底層容器提供隨機訪問迭代器,而鍊錶並沒有提供。所謂的隨機訪問迭代器是指通過該迭代器可以訪問容器中任一元素,而鍊錶的迭代器只能自增或者自減,並不能隨機訪問任一元素。

資料結構與演算法-鍊錶(下)

資料結構 棧與佇列

題目 1.編寫函式,採用鏈式儲存實現棧的初始化 入棧 出棧操作 2.編寫函式,採用順序儲存實現棧的初始化 入棧 出棧操作 3.編寫函式,採用鏈式儲存實現佇列的初始化 入隊 出隊操作 4.編寫函式,採用順序儲存實現佇列的初始化 入隊 出隊操作 5.編寫乙個主函式,在主函式中設計乙個簡單的選單,分別除錯...

資料結構 棧與佇列

棧的原則是後進先出,即插入與刪除元素均在棧頂進行。獲取棧頂元素 s.top 佇列的原則是先進先出,即插入資料在隊尾進行,刪除資料在隊頭進行。獲取隊頭元素 q.front 思路 用兩個棧,乙個棧用來進隊,乙個棧用來出隊,當資料進入佇列的時候,我們將其壓入乙個棧,當資料出隊的時候,我們將儲存在棧內的資料...

資料結構 棧與佇列

1.順序棧 基本操作 typedef int elemtype 定義 順序棧 typedef struct sqstack 判空 bool stackempty sqstack s 進棧 bool push sqstack s elemtype x 出棧操作 bool pop sqstack s e...