資料結構與演算法筆記 棧及棧的應用

2021-10-10 21:34:09 字數 3984 閱讀 6331

目錄前言

一、棧的結構

二、基本操作

三、棧的應用

1. 棧模擬

(1)出棧序列判斷

(2)表示式求值  luogu p1175

(3)判斷括號是否匹配 luogu p739

2.凸包/凸殼 luogu p5155

3.遞迴

4.單調棧 

總結

前言

棧(stack)是一種後進先出(lifo, last in first out)的資料結構,這是一種非常基礎的資料結構,在很多地方,尤其是dfs和單調棧中有廣泛的應用。

一、棧的結構

可以使用c++ stl中的stack實現,也可以自己模擬。

通常用乙個陣列和乙個指標模擬乙個棧,陣列用於儲存元素,指標top表示棧頂,入隊時將top向後移動,出隊時將top向前移動。

棧並不需要支援訪問任意元素,所以在某些情況下會用鍊錶模擬棧。

bool initstack(sqstack &s)

bool isemptystack(sqstack s)

bool push(sqstack &s, data e)

*(s.top++) = e;

return true;

}bool pop(sqstack &s, data &e)

bool showstack(sqstack &s)

}

棧模擬以該出棧序列為出棧時的具體過程,當不滿足時,棧中元素將無法全部出棧

#include#includeusing namespace std;

int m = ; //從m[1]開始

//按照1~n的順序輸入,實際任意有序序列都可以判斷

bool judgestack(int a, int n)

}return st.empty();

}int main()

給出中綴表示式求字尾表示式,並返回字尾表示式計算過程和計算結果。

方法一、用棧實現中綴轉字尾和字尾計算

方法二、構建表示式二叉樹求解

可以用來求凸包,但是因為凸包需要訪問最後22個元素,用以判斷折線的方向,所以不能用stl的stack

遞迴演算法都會用到棧,只不過系統會自動維護。

如果想使用非遞迴演算法,那麼就需要自己實現棧了。

定義: 

單調棧就是棧內元素單調按照遞增(遞減)順序排列的棧,分為單調遞增棧和單調遞減棧。

適用問題

在佇列或陣列中,我們需要通過比較前後元素的大小關係找尋到下乙個比他大(小)的元素來解決問題時通常使用單調棧。進而可以在較小的複雜度內借助單調棧這一資料結構來解決此問題。

具體思路

for遍歷陣列,

單調遞增棧:找兩側第乙個小於本身的元素使用

單調遞減棧:找兩側第乙個大於本身的元素使用

個人理解:

借助模板題 洛谷 p5788 單調棧 和後面的題解終於理清了遍歷陣列的過程時到底找尋的是哪乙個元素的第乙個大的最近元素是哪個元素

有兩種思路:首先該題要找大的,需要單調遞減棧

(1)從前往後遍歷,記錄當前元素i是哪些元素的右邊第乙個大於的值,元素i是彈出的每個棧頂元素的右邊第乙個大於的元素;(出棧找到右邊第乙個大於的元素,需要在最後乙個元素後面加上乙個元素為inf,保證棧的元素都能彈出)

(2)從前往後遍歷,考慮當前元素i的左邊的第乙個大於的值是哪乙個元素,即一直出棧到不在出棧為止,因為是單調遞減的,所以當前棧頂元素是左邊第乙個大於的元素。(入棧可以找到左邊第乙個大於的元素,若棧為空,則說明左邊無第乙個大於的元素)《這題因為是求單側的因此這種思路是採取從後往前遍歷的》

從以上兩種思路就可以在一次遍歷的過程中找到每個元素左右第乙個大於或小於的元素。

此題**如下:

#includeusing namespace std;

const int n = 3e6 + 10;

int a[n], stk[n], top = 0, n = 0;

int ans[n];

int main()

// stk[++top] = i;

// }

stk[0] = 0;

for (int i = n; i >= 1; i--)

for (int i = 1; i <= n; i++)

printf("%d ", ans[i]);

return 0;

}

單調棧的偽**模板:《不要死套模板》

/*

* 本偽**對應的是單調遞增棧

*共n個元素,編號為0~n-1

*/while(棧為空) 棧頂元素出棧; //先清空棧

a[n]=-1;

for(i=0;i<=n;i++)

將最後一次出棧的棧頂元素(即當前元素可以拓展到的位置)入棧;

更新最後一次出棧的棧頂元素其對應的值; //經歷過彈出元素後,當前元素i左邊第乙個小於的元素為此時棧頂top

} }

(1)視野問題 牛客 最優屏障

《單調遞減棧》   也可以用同一種思路經過兩次遍歷,從前往後和從後往前

#include#includeusing namespace std;

const int n = 5e4 + 7;

int a[n], v1[n], v2[n];

stackst;

//v1[i]表示第1~i個的山所有前向防禦力之和

//v2[i]表示第i~n個的山所有後向防禦力之和

//每個山單側的防禦力計算是借助單調棧來計算的。

void show(int v1, int v2, int n)

int main()

if(st.empty())

v1[j] += v1[j - 1] + num;

else

v1[j] += v1[j - 1] + num + 1;

st.push(a[j]); //必須等計算完,再加當前數字

}while(!st.empty()) st.pop();

//同理計算後向防禦力字首和

for(int j = n; j >= 1; j--)

if(!st.empty()) v2[j] += v2[j+1] + num + 1;

else v2[j] += v2[j+1] + num;

st.push(a[j]);

}//v1[n] = v2[1],因為

int x = 0, c = 0;

for(int j = 1; j <= n; j++)

if(v1[n] - v1[j] - v2[j + 1] > c)

printf("case #%d: %d %d\n",i, x, c);

}return 0;}/*

232 1 3

0311

30case #1: 2 2

54 5 2 6 3

0514

2241

50case #2: 3 2

*/

(2)最大矩形面積   此部分****於:

#includeusing namespace std;

int main()

s[++p]=a[i],w[p]=width+1; //經歷過棧彈出過程,找尋左邊第乙個小於元素,不僅要加上本身的1,還要加上彈出過程的總寬度}}

cout<(3)求最大區間

未完待續

資料結構 棧與棧的應用

棧是非常重要的線性資料結構之一,其中一端為棧頂,加入元素和取出元素全部在棧頂端進行,滿足lifo last in first out,後進先出 的性質。考慮這樣乙個問題 您需要寫一種資料結構,維護一系列數,初始為空。定義其中一端為頂,另一端為底,要求提供三種操作 1 格式 111x xx,表示在最頂...

資料結構與演算法 棧的應用

逆序輸出 輸出的次序和處理次序相反,而且遞迴的深度不容易預知。比如進製轉換,括號匹配 進製轉換 void convert stack char s,int n,int base while n 0 括號匹配 括號匹配 bool paren vector char v elseif s.empty e...

資料結構與演算法(4) 棧的應用

include include include using namespace std bool matchbrackets char pstr else if pstr i pstr i pstr i else s.top else if s.empty else int main char pt...