在閱讀《演算法導論》基本資料結構那一章時,看到了練習10.1-6 要求用兩個棧來實現佇列,於是好奇為什麼會存在這樣一種需求,在上網查閱了相關資料後,將收穫整理如下。其中參考**主要是 stackoverflow的乙個問題
一、如何用兩個棧來實現佇列
演算法基本思路:定義兩個棧,不妨稱為stackin和stackout,當接收到入隊的請求時,將元素壓入stackin,接收到出隊請求時,先檢測stackout是否為空,不為空則彈出stackout的棧頂元素;若為空,則逐個彈出stackin的元素並將其壓入stackout,直到stackin為空,此時再彈出stackout的棧頂元素即可。
可以這樣理解:佇列是fifo,那麼對於雙棧實現的佇列,第乙個進入的元素在stackin棧底,此時若想輸出它,只能先處理它之上的那些元素,處理方法即將這些元素從in轉移到out。最後乙個壓入out為原先in的棧底元素,也就是第乙個入隊的元素。所以此時彈出out的棧頂元素就是第乙個進入的元素了。我們注意到接下來第二,第三,....的元素在out中也已經排列好了,之後若想出隊,就彈出out中的元素就好了,直到為空,。
在c++標準庫提供的stack的基礎上實現這樣乙個佇列
templateclass stack
bool empty()
//將stl的stack重新封裝一下,把pop變為棧彈出的同時也返回值
t pop()
t top()
};templateclass queue
public:
bool empty()
void enqueue(t &e)
t dequeue()
};
二、為什麼會有用兩個棧來實現佇列的需要?
2.1 一些函式式語言,如haskell, ml, lisp等內建了list型別, 一般是單向鍊錶。這種鍊錶很適合實現乙個棧結構,因為我們只需要在表頭新增乙個節點作為入棧,或是去掉表頭作為出棧,這只需要o(1)的時間。但是若用這種內建鍊錶實現佇列的話,入隊的操作是o(1)的實現,但是出隊的操作需要我們遍歷到表尾,這需要o(n)的時間。
那麼此時用兩個棧來實現佇列,我們可以將出隊的時間經過分攤以後將時間複雜度降為o(1),所以在這些語言中用雙棧構建佇列可能是一種好的選擇。
2.2一些額外的函式功能對於雙棧搭建的佇列而言更好實現
例如findmax,findmin等查詢棧或佇列中最小值的函式。
帶有這種功能棧的實現思路
#include#include#define element 0
#define min 1
#define max 2
using namespace std;
templateclass stack
s.push(v);
} bool empty()
//將stl的stack重新封裝一下,把pop變為棧彈出的同時也返回值
t pop()
t top()
//由於壓入時的比較,我們知道棧頂元素的那個向量儲存的是當前棧中所有元素的最大值和最小值
t findmax()
t findmin()
};
由於棧filo的性質,我們維護最大值最小值時比較容易,因為每個元素所在的那個向量的最大值、最小值都是和之前入棧的元素進行比較得到的。所以當某個元素出棧時,不需要再去檢查這個元素之前的那些元素是否需要更新。
但是對於佇列而言,其fifo的性質使得我們很難維護最大值最小值。當我們現在要入隊乙個元素時,這個元素所在那個向量的最大值最小值,需要跟隊伍中已存在的元素進行比較。之後我們如果出隊乙個元素,因為first in firs out,當前隊伍中最早入隊的元素出隊了,但是我們知道這個排在這個元素後面的那些元素,它們所在的向量的最值均與這個元素比較過,所以這個元素出隊後,剩下的每個元素均需要重新與在其前面的元素進行比較,確認最大值、最小值是否發生改變。
所以這個出隊時維護最大值、最小值的所耗費的時間是很難接受的。這裡需要說明一點的是,對於普通方式實現的佇列,不需要像上述stack那樣為每個元素維護乙個向量。它只需為整個佇列,維護兩個變數即可。這樣出隊時,只需進行o(n)的比較即可,否則的話需要進行o(n^2)此比較。
那有沒有更好的方式去實現這樣乙個能夠維護最大值最小值的佇列呢?有的,就是利用上面實現的那個已具有這些功能的兩個棧即可。
思路是這樣:當要求佇列的最大值/最小值時,我們可以比較兩個棧中的最大值/最小值,從而確定佇列中的最大值/最小值,拿到兩個棧中最大值/最小值是o(1),比較得到佇列的最大值/最小值也是o(1),所以我們可以得到乙個在時間上複雜度更優的功能佇列。不過需要注意處理兩個棧中有乙個棧為空的特殊情況。
templateclass queue
public:
bool empty()
void enqueue(t &e)
t dequeue()
t findmax()
} }t findmin()
} }};
用兩個棧實現乙個佇列 用兩個佇列實現乙個棧
做題之前,我們先來回顧一下 棧和佇列的相同點以及不同點 便於做題時的應用!1.區別與聯絡 相同點 1 棧和佇列都是控制訪問點的線性表 2 棧和佇列都是允許在端點處進行資料的插入和刪除的資料結構 不同點 1 棧遵循 後進先出 lifo 的原則,即只能在該線性表的一頭進行資料的插入和刪除,該位置稱為 棧...
用兩個棧實現乙個佇列,用兩個佇列實現乙個棧
t deletehead 頭部刪除節點 while s1.empty t ret s2.top s2.pop return ret private stacks1 stacks2 問題2 用兩個佇列實現乙個棧 問題分析 用兩個佇列實現乙個棧,刪除時,由於佇列是先進先出的,而棧是後進先出,因此假設現在...
用兩個棧實現乙個佇列 用兩個佇列實現乙個棧
思路 棧 先進後出,佇列 先進先出 如果轉化 1.將內容先push進乙個棧instack,2.判斷outstack是否為空,空 將棧instack中的元素pop 刪除並返回陣列的最後乙個元素 並push進outstack,非空 直接出棧 3.出棧時,先push進instack先從outstack出來...