## 定義
所謂的 STL 就是 Standard Template Library,裡面有很多好用的資料結構與函數
比如之後會單獨拉出來的 stack 和 queue,還有下面會介紹的 vector 等等
這些資料結構都會介紹初始化方式、常用函式、資料結構的特色等等
因為我們都用 `#include<bits/stdc++.h>`,所以不需要再特別載入標頭檔
## vector(向量)
vector 可以簡單理解成可以在尾端動態增加/刪減元素的 array,先介紹初始化的方式
```cpp=
#include<bits/stdc++.h>
using namespace std ;
int main() {
vector<int> v1 ; // v1 = {} size = 0
vector<int> v2(3) ; // v2 = {x, x, x}, size = 3
vector<int> v3(2, 1) ; // v3 = {1, 1} size = 2
vector<int> v4 = {1, 2, 3, 4} ; // v4 = {1, 2, 3, 4} size = 4
return 0 ;
}
```
還有很多種初始化的方式,但基本上只要記住這些就可以了
---
iterator 是一種抽象指標,可以用來存取 STL 資料結構的元素,以下是搭配 vector 的範例
```cpp=
#include<bits/stdc++.h>
using namespace std ;
int main() {
vector<int> v = {1, 2, 3, 4, 5} ;
auto it = v.begin() ; // vector<int>::iterator it ;
for (;it!=v.end();it++)
cout << *it << ' ' ;
// next(it) -> it+1, prev(it) -> it-1
it = find(v.begin(), v.end(), 2) ;
int position = it - a.begin() ;
if (it == v.end()) // not exist
cout << "2 isn't in v\n" ;
else
cout << "The position of 2 in v is " << position << '\n' ;
v.insert(v.begin()+1, 6) ; // 1 6 2 3 4 5
vector<int> v1 = {9, 10} ;
v.insert(v.end(), v1.begin(), v1.end()) ;
v.erase(v.begin()+2) // erase v[2] ;
v.erase(v.begin()+1, v.begin()+3) ; // erase v[1]~v[3] ;
return 0 ;
}
```
以上的 `v.begin()` 就是 v 的第一個元素地址,`v.end()` 是"最後一個元素"往後一個的地址
但 insert 和 erase 功能不太常用,只是做為 iterator 的範例
接著就是大小、遍歷、排序、翻轉等等操作的實現
```cpp=
#include<bits/stdc++.h>
using namespace std ;
int main() {
vector<int> v1 ; // v1 = {}, size = 0
// vector<int> v2(3) ; // v2 = {x, x, x}, size = 3
// vector<int> v3(2, 1) ; // v3 = {1, 1}, size = 2
vector<int> v4 = {4, 3, 2, 1} ; // v4 = {4, 3, 2, 1}, size = 4
v1.push_back(-1) ; // v1 = {-1} size = 1
cout << v1[0] << ' ' << v1.size() << '\n' ; // -1 1
v1.clear() ; // v1 = {}, size = 0
int len = v4.size() ;
for (int i=0;i<len;i++) // 照順序輸出
cout << v4[i] << ' ' ;
cout << '\n' ;
for (auto it=v4.begin();it!=v4.end();it++) // 照順序輸出
cout << *it << ' ' ;
cout << '\n' ;
sort(v4.begin(), v4.end()) ; // 排序
for (int i=0;i<len;i++)
cout << v4[i] << ' ' ;
cout << '\n' ;
reverse(v4.begin(), v4.end()) ; // 翻轉
for (int i=0;i<len;i++)
cout << v4[i] << ' ' ;
cout << '\n' ;
v4.clear() ;
return 0 ;
}
```
## pair / tuple
先聲明 tuple 不是 STL 的一部分,但因為在使用上可以當作 pair 的延伸,所以在這邊一起講
pair 可以同時儲存兩個不同 type 的元素,tuple 可以儲存多個不同 type 的元素
而且它們兩個都可以被比較,兩個結構的比較方式是先比較第 $0$ 項,再比較第 $1$ 項,以此類推
```cpp=
#include<bits/stdc++.h>
using namespace std ;
#define FF first
#define SS second
int main() {
pair<int, int> Pii = {1, 2} ; // 初始化
pair<int, string> Pii2 = make_pair(3, "abcd") ;
cout << Pii.FF << ' ' << Pii.SS << '\n' ;
cout << Pii2.FF << ' ' << Pii2.SS << '\n' ;
tuple<int, int, int> T1(1, 2, 3) ; // 初始化
tuple<char, char, int, int> T2 = make_tuple('a', 'b', 8, 9) ;
cout << get<1>(T1) << '\n' ; // 取出第 1 項 (index 0 ~ n-1)
char c1, c2 ;
int n1, n2 ;
tie(c1, c2, n1, n2) = T2 ; // 將 c1, c2, n1, n2 設為 T2 裡的元素
cout << c1 << ' ' << c2 << ' ' << n1 << ' ' << n2 ;
return 0 ;
}
```
由於這種可以被比較的方式,sort 也可以用在這兩個結構上面
當然在多個不同情況下,struct
## set (集合) / unorded_set
所謂的集合就是數學意義上的集合,裡面的元素不會重複,不過這裡的 set 會自動排序
```cpp=
#include<bits/stdc++.h>
using namespace std ;
int main() {
set<int> st ; // 初始化
st.insert(1) ;
st.insert(2) ;
st.insert(3) ;
st.insert(3) ;
for (int num: st) // 遍歷輸出
cout << num << ' ' ;
cout << '\n' ;
if (st.find(1) != st.end()) // 查找元素方式
cout << "Can find 1 in st\n" ;
st.erase(2) ;
for (int num: st) // 遍歷輸出
cout << num << ' ' ;
cout << '\n' ;
for (auto it=st.begin();it!=st.end();it++) // 遍歷輸出
cout << *it << ' ' ;
cout << '\n' ;
// 基本上 unorded_set 跟 set 用法一樣
// 但順序是打亂的,不會照值大小排序
return 0 ;
}
```
## priority_queue (優先 queue)
(建議先看過 queue 和樹論中的 heap 再來讀)
是一種特殊的 Queue,其中的每個元素都有一個優先權,取出時會選擇優先權最高的那個元素
實作方法最常用的是 Heap,在樹論有介紹過,當時只有最大最小值,這裡可以調整
enqueue、dequeue 的時間複雜度都是 $O(log\ n)$
```cpp=
#include<bits/stdc++.h>
using namespace std ;
struct cmp { // 比較
bool operator()(const int &a, const int &b) const {
return a > b ;
}
};
int main() {
priority_queue<int> pq1 ; // 大到小 top 為最大
priority_queue<int, vector<int>, greater<int>> pq2 ; // 小到大 top 為最小
priority_queue<int, vector<int>, cmp> pq3 ; // 小到大 top 為最小
pq1.push(1) ;
pq1.push(2) ;
cout << pq1.top() << '\n' ;
pq3.push(5) ;
pq3.push(6) ;
cout << pq3.top() << '\n' ;
while (!pq1.empty()) { // or while(pq1.size())
cout << pq1.top() << ' ' ;
pq1.pop() ;
}
cout << '\n' ;
while (!pq3.empty()) {
cout << pq3.top() << ' ' ;
pq3.pop() ;
}
cout << '\n' ;
return 0 ;
}
```
由於用法比較特別,目前只要記起來就好,如果要更多原理可以去看 C++ 的 STL document
## map / unorded_map
所謂的 map 具有 key : value,就跟數學中的 function 的概念一樣,f(key) = value
在 map 當中會以 pair 的形式去儲存 (key, value),且 key 會由小到大排序
```cpp=
#include<bits/stdc++.h>
using namespace std ;
int main() {
map<int, int> mp1 ; // 初始化
map<char, int> mp2 ;
mp1[2] = 7 ;
mp1[1] = 8 ;
mp2['a'] = 5 ;
mp2['b'] = 10 ;
for (auto it=mp1.begin();it!=mp1.end();it++) // 遍歷 mp1
cout << it->first << ' ' << it->second << '\n' ;
if (mp2.find('c') != mp2.end()) // 找 mp2 裡有沒有 c
cout << "c is a key in mp2.\n" ;
else
cout << "c isn't a key in mp2.\n" ;
mp2.erase('b') ; // 刪除 mp2 裡面的 key: b
for (auto it=mp2.begin();it!=mp2.end();it++) // 遍歷 mp2
cout << it->first << ' ' << it->second << '\n' ;
// unorded_map 跟 map 用法不太一樣
unordered_map<int, int> mp3 ; // 初始化
unordered_map<char, int> mp4 = {{'a', 6}, {'b', 12}} ;
mp3.insert({2, 9}) ;
mp3.insert({3, 10}) ;
for (auto it=mp4.begin();it!=mp4.end();it++) // 遍歷 mp4
cout << it->first << ' ' << it->second << '\n' ;
// 其餘其餘功能一樣就不展示
return 0 ;
}
```