---
# System prepended metadata

title: STL

---

## 定義
所謂的 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 ;
}
```


