棧和佇列在實現結構上可以有陣列和鍊錶兩種形式:
陣列實現比較容易;
用鍊錶結構比較複雜,因為有指標。
棧結構的基本操作:
pop 從棧頂彈出乙個元素;
top或peek 只訪問棧頂元素,但是不彈出刪除;
push 向棧頂壓入乙個元素;
size 返回當前棧中的元素個數;
佇列的基本操作:
與站操作不同的是,push操作為在隊頭加入元素;
而pop操作是從佇列尾部彈出乙個元素。
棧和佇列的基本操作都是時間複雜度為o(1)的操作;
棧可以看做一條射線,底部是固定的;佇列是一條直線,操作在兩端進行,一端用來進入佇列,一端用來出佇列;
特殊結構:雙端佇列結構為首尾都可以壓入和彈出元素!!!
優先順序隊列為根據元素的優先順序值,決定元素的彈出順序;優先順序佇列的結構堆結構,並不是線性結構。
樹的遍歷方式有先序、中序、後序以及按層遍歷!
圖的遍歷方式:深度優先遍歷(dfs)和寬度優先遍歷(bfs)!
深度優先遍歷可以用棧實現:元素入棧的順序就是深度優先遍歷的順序也就是訪問的順序;
寬度優先遍歷用佇列實現:元素進佇列的順序就是寬度優先遍歷的順序,也就是訪問的順序。
平時使用的遞迴函式實際上用到了提供的函式系統棧,遞迴的過程可以看做遞迴函式依次進入函式站的處理過程!
所有用遞迴函式可以做的過程一定更可以用非遞迴的方式實現;
案例一:
實現乙個特殊的棧,在實現棧的基本功能的 基礎上,再實現返回棧中最小元素的操作getmin。
要求:1. pop push getmin操作的時間複雜度丟失o(1)/
2. 設計的棧型別可以使用現成的棧結構。
一共有兩種方式,兩種方式都是利用兩個棧,其中乙個棧用來儲存正常的資料元素,記為stackdata,另乙個棧用來儲存每一步的最小值,記為stackmin.。
第一種方式中,只有當前數小於等於stackmin的棧頂時,該數放入stackmin。在彈出的時候,只有stackdata當前值等於stackmin棧頂的時候才會彈出。
由壓入規則可知,stackmin始終記錄的都是壓入的stackdata當前的最小值。再彈出的時候,stackmin在stackdata彈出的時候,依舊維護著stackdata中的最小值。
另一種方式中,當前數和stackmin棧頂元素比較,較小的壓入stackmin。如果當前數不比stackmin中的數小,那麼就依舊向stackmin中壓入上一次壓入的值。
stackmin中始終記錄著stackdata中每一步的最小值,不管是壓入還是彈出。並且stackdata和stackmin是同步彈出的,不需要比較。
由上面的兩種方式可以知道。它們都是利用第二個棧stackmin來儲存stackdata每一步的最小值。
並且這兩種方式的時間複雜度都是o(1)額外空間複雜度都是o(n),
區別在於方案一的stackmin在壓入時稍微節省空間,彈出時稍微浪費時間,方案二stackmin在壓入時稍微浪費空間,彈出時節省時間,因為彈出的時候不需要比較,同步彈出就可以。
class solution
void pop() else if(!datastack.empty()&&(datastack.top()!=minstack.top()))
}int top()
int min()
};上面的**是方案一的實現!!
案例二:編寫乙個類,只能用兩個棧結構實現佇列,支援佇列的基本操作(add,poll,peek)。對應c++佇列中的(push pop front empty)
需要注意的是棧是先進後出,但是佇列是先進先出,用兩個棧正好可以實現乙個佇列。
實現方式為:
乙個棧為壓入棧,stackpush,壓入資料時只向這個棧壓入資料。
另乙個棧是彈出棧,stackpop,在彈出資料時只從這個棧彈出資料。
因此將stackpush中的資料倒入stackpop棧中資料的順序就倒過來了。
再從stackpop中彈出資料時,順序就和佇列一樣了!!!
有兩個需要注意的點:
1. 如果stackpush要往stackpop中倒入資料,那麼必須要把stackpush中的所有資料一次性到完。
2. 如果stackpop中有資料,則不能發生倒資料的行為。
不能違反上面兩點規則,否則會發生錯誤。
class twostack ;
具體實現如上面的程式所示,但是需要時刻注意的是那兩個不能違反的規則,否則會發生錯誤!!
從stackpush倒向stackpop這個行為可以選擇在很多方法中(add poll peek)包含該邏輯,但要保證倒入資料的兩個注意點不被違反。
案例三:實現乙個棧的逆序,但是只能用遞迴函式和這個棧本身的操作來實現,而不能自己申請另外的資料結構。
首先介紹第乙個函式:這個函式的功能是移除棧底元素並返回。利用了遞迴。
public int get(stackstack)else
}對於下面的例子來說,棧中原來的樣子為:
上面的程式執行完畢之後,1和2又被重新壓入棧中,3被返回。
上面的方法被記為get方法。
下面介紹乙個函式:把棧中的元素逆序的主方法。也是利用了遞迴。
public void reverse(stackstack)
//首先需要實現的刪除棧底元素,並且返回,這個函式也是利用遞迴函式實現,
int getstack(vector& a,int n)
else
}void reverse(vector& b,int n )else}};
具體的實現如上所示,上面的程式中將vector當做了stack來用!!
案例四:乙個棧中元素型別為整形,現在想將該棧從頂到底按照從大到小的順序排序,只允許申請乙個棧,除此之外,可以申請新的變數,但不能申請額外的資料結構,如何完成排序?
方法為將想要排序的棧記為stack,申請的輔助棧記為help,在stack上執行pop操作,彈出的元素記為current,這個current要和help中的棧頂元素進行比較,如果current小於或者等於help棧頂元素的話,就直接push進入help棧;如果current大於help的棧頂元素,那麼將help中的元素逐漸彈出並且壓回到stack中,直到current小於等於help中的棧頂元素,然後將current壓入棧。重複執行上面的操作,直到stack中沒有元素,然後將help中的元素彈出壓入到stack中。
class twostacks elseelse{
current=numbers.back();
numbers.pop_back();
while(!help.empty()){
if(current需要時刻注意什麼時候pop和什麼時刻push!!!
棧和佇列的基本性質
棧是一種特殊型別的線性表,訪問 插入 刪除只能發生在棧頂。vector繼承自list類,所以裡面有實現相關的介面,stack類是其中的乙個實現類。peek 返回棧頂元素,push 壓入棧,pop 刪除棧頂元素並且返回。佇列是一種 fifo先進先出的資料結構。元素被追加到佇列的末尾,從頭部進行刪除。p...
單調棧的基本性質介紹
單調棧的定義 單調棧就是棧內元素單調遞增或者單調遞減的棧,單調棧只能在棧頂操作。為了更好的理解單調棧,則可將單調棧用生活情形模擬實現,例如 我們借用拿號排隊的場景來說明下。現在有很多人在排隊買可樂,每個人手裡都拿著號,越靠前的人手裡的號越小,但是號不一定是連續的。小明拿了號後並沒有去排隊,而是跑去約...
棧和佇列基本應用
一 棧 棧 是限定僅在表尾進行插入或刪除操作的線性表,表尾段稱為棧頂,表頭段稱為棧底,棧有稱後進先出線性表。棧有順序棧和鏈棧。個人總結 棧的操作可以在陣列的基礎上,也可以運用stack。陣列的操作就不多說了,現在總結一下stack。stack基本應用。標頭檔案 include stack stack...