# DS Stack
{%hackmd theme-dark %}
## 堆疊
:::info
* LIFO
* 只能從**頂端**取/刪資料
* 只能從**頂端**加資料
:::
## 實作
### Array-based
```cpp
struct Stack{
int arr[MAXN], now;
Stack(): now(0) {}
int top(){
return arr[now-1];
}
void pop(){
--now;
}
void push(int val){
arr[now++] = val;
}
int size(){
return now;
}
};
```
### Pointer-based
```cpp
template <typename T>
class Stack {
struct Node {
T data;
Node *next;
Node(const T &d, Node *n = nullptr) : data(d), next(n) {}
};
Node *top;
int _sz;
public:
Stack() : top(nullptr), _sz(0) {}
bool empty() const { return top == nullptr; }
void push(const T &d) {
top = new Node(d, top);
_sz++;
}
T top() {
return top->data;
}
void pop() {
Node *tmp = top;
top = top->next;
delete tmp;
_sz--;
}
int size() { return _sz; }
~Stack() {
while (!empty()) pop();
}
};
```
## 例題
### Leetcode - backspace string compare
https://leetcode.com/problems/backspace-string-compare/description/
#### 題目:
模擬鍵盤輸入小寫字母跟backspace,問最後這兩個字串是否一樣
#### 解法:
遇到一般字元就 push,遇到backspace就pop,記得pop前檢查stack是不是空的。
### 括號匹配
#### 題目:
有很多由括號組成的字串問是否合法匹配
#### 解法:
遇到左括號就 push,遇到右括號就 pop,如果 pop 時 stack 是空的(多餘的右括號)或是結束時 stack 不是空的就不合法。
* 這題不用 stack 也能解
### UVA 514
#### 題目:
有一個火車站,出去及進來都只有一條路
有一對列按照編號順序排列的火車
是否能按照給定的順序出車站?
#### 解法:
stack 直接模擬
### 中序轉後序
#### 題目:
給中序式請轉成後序式
#### 解法:
注意運算子的優先順序,數字直接 push,運算子需先將優先度高的算完,再 push 進 stack。
```cpp
bool InfixToPostfix(List<string> &exp, List<string> &ret) {
Stack<string> oper;
// List<string> ret;
while (!exp.empty()) {
string cur;
exp.front(cur), exp.delete_front();
// cerr << cur << endl;
if (cur == "(") {
oper.push(cur);
} else if (cur == ")") { // -> pop all the operators until "("
string oper_cur;
while (!oper.empty()) {
oper.gettop(oper_cur);
oper.pop();
if (oper_cur == "(") break;
ret.push_back(oper_cur);
}
} else if (isOperator(cur[0])) {
string _top = "";
// higher priority operator must be popped(calculated) first
if (!oper.empty()) oper.gettop(_top);
while (!oper.empty() && priority(_top[0]) >= priority(cur[0])) {
ret.push_back(_top);
oper.pop();
if (!oper.empty()) oper.gettop(_top);
}
oper.push(cur);
} else if (isOperand(cur)) { // operand can be pushed directly
ret.push_back(cur);
}
}
string o;
while (!oper.empty()) { // handle all uncalculated operators
oper.gettop(o);
oper.pop();
if (o != "(") ret.push_back(o);
}
return true;
}
```
### 運算式結果
#### 題目:
給一運算式求值是多少
#### 解法:
先依上題轉成後序,然後每次算完就放入堆疊,最後答案就是堆疊最頂端(堆疊應只剩一個data)
```cpp
bool evaluate(List<string> strList, int &ret) {
ret = 0;
List<string> tmp = strList;
Stack<int> s;
while (!tmp.empty()) {
string cur;
tmp.front(cur), tmp.delete_front();
if (isOperator(cur[0])) {
int a, b;
s.gettop(b), s.pop();
s.gettop(a), s.pop();
switch (cur[0]) {
case '+':
s.push(a + b);
break;
case '-':
s.push(a - b);
break;
case '*':
s.push(a * b);
break;
case '/':
if (b == 0) {
cout << "### Error: Divided by ZERO! ###\n";
return false;
}
s.push(a / b);
break;
}
} else {
int num = atoi(cur.c_str()); // convert string to int
s.push(num);
}
}
s.top(ret);
return true;
}
```
## 延伸 - 單調堆疊
:::info
維護單調性的堆疊
:::
### 實作
* 如果堆疊為空或比 top 小的進堆疊
* 如果比 top 大就 pop 掉 top
## 例題
### 直方圖最大矩形
[https://leetcode.com/problems/largest-rectangle-in-histogram/](https://leetcode.com/problems/largest-rectangle-in-histogram/)