# STL
在C++裡面的函式中,有一些內建好用資料結構,這些資料結構都是用一種叫型別模板(template)的東西去包裝,而這些資料結構包裝起來就變成了標準模板庫(standard template library)
那STL裡面有什麼呢?
首先我們先來講解STL的三大容器 vector、deque跟list
## vector
### vector介紹
原生C++的陣列是使用一連串的記憶體位置來儲存資料,但是當我們宣告完陣列大小後就沒辦法再修改了。
這時候我們就可以用STL裡的vector!!
vector簡單來講就是一個可以變長變短的陣列。在某些情況下,可以伸縮的陣列在解題上可以方便許多。
首先,我們來宣告一個vector,以下是一些常見的vector宣告方法
```cpp=
vector<int> vec; //一般的宣告
vector<int> vec = {1, 2, 3}; //宣告一個有1,2,3的vector
vector<int> vec(10); //宣告長度為10的vector
vector<int> vec(10,1); //宣告長度為10的vector,並將全部填為1,如果後面沒有參數,則填入0
```
如果我們已經知道資料的大小是多少的話,就可以把vector當一般陣列一樣。
那如果我們不知道要輸入多大的資料,我們可以使用push_back(emplace_back)來自動新增元素並配置記憶體到vector的尾端
```cpp=
vector<int> vec;
vec.push_back(1);
vec.emplace_back(1);
```
push_back跟emplace_back是差不多的東西,但在某些地方上有些微的不同
以pair當作例子來看
```cpp=
vector<pair<int,int>> v; //before C++11
v.push_back(make_pair(1, 1));
v.push_back({1, 1}); //C++11
v.emplace_back(1, 1);
```
push_back是先建構一個臨時的物件,複製到容器尾端裡後再釋放臨時物件的記憶體
而emplace_back是直接呼叫建構函式建構在容器尾端
所以通常emplace_back的效率會比push_back還來的好
以下是vector常用的操作
`vec.size()` 回傳vector的大小 $O(1)$
`vec.reserve(size)`預留size大小的空間 如果要重新配置記憶體 $O(n)$,否則 $O(1)$
`vec.empty()` 回傳一個布林值,如果vector是空的就回傳true,否則回傳false, $O(1)$
`vec.clear()` 清空vector,$O(n)$
### vector常見用途
以下兩種是vector的遍歷方式
```cpp=
vector<int> vec = {1, 2, 3};
for(int i=0;i<v.size();i++) cout << v[i] << ' ';
for(int i: vec) cout << i << ' '; // C++11 以上
```
可以看個人喜好或是情況來決定要用哪一種遍歷方式
vector的迭代器是屬於隨機存取迭代器,所以說我們可以把兩個vector的指標做運算,再搭配二分搜求出任一個數字在第幾個位置
```cpp=
vector<int> vec;
vec.begin() //vector的第一個位置
vec.end() //vector最後一個位置的後一位
int N = vec.end() - vec.begin(); //算出vec的size
```
迭代器也可以拿來遍歷vector
```cpp=
for(auto it = vec.begin(); it != vec.end(); it++) cout << *it;
```
vector也可以拿來當作連接串列,用來存圖上的邊和權重
```cpp=
vector<int> vec1[N];
for (int i = 0; i < m; ++i) { //無權單向
int a, b;
cin >> a >> b;
vec[a].push_back(b);
}
vector<pair<int,int>> vec2[N];
for (int i = 0; i < m; ++i) { //有權雙向
int a, b, w;
cin >> a >> b >> w;
vec2[a].push_back(make_pair(b, w));
vec2[b].push_back(make_pair(a, w));
}
```
### 注意事項
vector在配置記憶體時蠻花時間的,如果確定好大小的話,先reserve()後再用push_back,效率會比較好
### 習題
[TOJ 575](https://toj.tfcis.org/oj/pro/575/)
[zerojudge b298](https://toj.tfcis.org/oj/pro/575/)
:::spoiler 解答
TOJ 575
```cpp=
#include <bits/stdc++.h>
using namespace std;
#define bobotou ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define F first
#define S second
using pii = pair<int, int>;
const int MAXN = 1000005;
vector<int> vec[MAXN];
vector<pii> peo;
signed main(){
bobotou;
int N, K;
cin >> N >> K;
for (int i = 0; i < K; i++){
int tmp1, tmp2;
cin >> tmp1 >> tmp2;
peo.emplace_back(tmp1, tmp2);
}
for(int i = 0; i < K; i++){
vec[peo[i].F].emplace_back(peo[i].S);
vec[peo[i].S].emplace_back(peo[i].F);
}
for(int i = 1; i <= N; i++){
sort(vec[i].begin(),vec[i].end());
for(int j = 0; j < vec[i].size(); j++){
if(j != 0) cout << ' ';
cout << vec[i][j];
}
cout << '\n';
}
}
```
zerojudge b298 (vector + queue)
```cpp=
#include <bits/stdc++.h>
using namespace std;
#define bobotou ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define pb(x) push_back(x)
#define F first
#define S second
const int MAXN = 100005;
vector<int> vec[MAXN];
bool poll[MAXN];
signed main(){
bobotou;
int N, M , L , Q;
int tmp1, tmp2;
cin >> N >> M >> L >> Q;
for(int i = 0; i < M; i++){
cin >> tmp1 >> tmp2;
vec[tmp1].pb(tmp2);
}
queue<int> q;
for(int i = 0; i < L; i++){
cin >> tmp1;
q.push(tmp1);
while(!q.empty()){
int x = q.front();
q.pop();
if(poll[x]) continue;
poll[x] = true;
for(auto i : vec[x]) q.push(i);
}
}
for(int i = 0; i < Q; i++){
cin >> tmp1;
cout << (poll[tmp1] ? "TUIHUOOOOOO\n" : "YA~~\n");
}
}
```
:::
## deque
deque 念法(ㄉㄟˋㄎㄜˇ )
中文叫雙向隊列
宣告寫法
```cpp=
deque<int> dq;
```
簡單來講就是可以在首尾新增、刪除元素的vector
大致上跟vector差不多,所以就直接講用途
`dq.push_front()` 在最前面放入元素
`dq.push_back()` 在最後面放入元素
`dq.pop_front()` 移除前面的元素
`dq.pop_back()` 移除後面的元素
`dq.front()` 回傳最前面的元素
`dq.back()` 回傳最後面的元素
`dq.size()` 回傳deque的大小
`dq.empty()` 回傳一個bool,如果為空true,否則false
同樣的也可以像vector一樣用emplace來壓常數
跟vector一樣也是隨機存取迭代器,所以也可以把兩個迭代器指標做運算
### deque常見用途
sliding window
DP的單調對列優化
### 注意事項
deque雖然比vector的功能還要來的多,但是deque卻比vector還要慢很多,所以能用vector達成的盡量用vector來達成。
後面提到的適配器(Container Adapters)很多內建也都是deque,所以我們可以把那適配器容器改成vector來增加效率。
### 例題
## list
STL的list是由一種叫連結串列(linked-list)來包裝
但是list其實在競程中沒有很常用到
而且在解題時我們也可以用陣列+struct來取代list
如果想要知道更多list的內容的話可以看[這篇文章](https://hackmd.io/@Zero871015/H12vTu8aX?type=view)
### 例題
## stack
一種先進後出的資料結構,由資料的同一端開口加入資料(push)或刪除資料(pop)。
### 實作
```cpp=
```
生活上的例子:賣場的推車(由同個方向加入推車或拿走推車)
## queue
與stack語法類似,最大的不同是stack是後進先出,而queue則是先進先出
## priority_queue
## set
## map
## pair
## bitset