C++ 常用 STL


STL 容器

STL 的宣告方式都是 資料結構 <資料型態> 名字!
資料型態都可以自己替換

vector

動態長度的陣列! 可以配合 range-based for loop 使用。
雖然是動態長度,但不代表可以隨便戳大小以外的 index 喔!
動態長度只是代表你可以 push_back, pop_back 改變陣列大小而已

複雜度:

插入: O(n)
刪除: O(n)
搜尋: O(n)

vector <int> a(100, 3); // 長度為 100,初始值都為 3 的 vector
vector <vector<int> > b(3, vector <int> (2, -1)); // 3 * 2 ,初始 -1 的二維 vector 

for(int x : a) cout << x << ' '; // 印出裡面所有東西
sort(a.begin(), a.end()); // 排序

a[2] = 1;
a.push_back(2); // 最後面加上一個 2 (所以是第101個元素)
a.pop_back();  // 移除最後一個元素
int n = a.size(); // 長度

map

map 可以用來將一個 key map 到一個 value
key 可以是 int 以外的資料型態! 
要遍歷一次 map 的話需要用到 map 自己的 iterator,打出來很長
for (map <string,int>::iterator it = mp.begin();it != mp.end();it++)
我們下面直接用 auto 配上 range-based for loop 就能很輕鬆的跑過去!

複雜度:

插入: O(logn)
刪除: O(logn)
搜尋: O(logn)

map <string,int> mp; // key: string, value: int

mp["Hi"] = 2;
mp.erase("Hi"); // 刪除

for(auto it : mp){ // 迴圈跑過 map 裡面的值
    cout << it.first << ' ' << it.second << '\n';
    // .first 是 key, .second 是 value
}

if(mp["123"]) cout << "YES"; 
else cout << "NO";
// 輸出 NO

auto it = mp.lower_bound("Hi"); // 是找 key,不是 index! 沒找到會回傳 mp.end()
mp.erase(it); 

set / multiset

會幫你把裡面的東西排序好。每個操作都是 O(logn)的時間。
set 不能有重複的元素,multiset 可以。
如果你在 set 加入兩個一樣的元素,程式不會報錯,就只是裡面只會有一個。
而跟 map 一樣,要取用 set 裡面的東西需要用到他的 iterator,
要取得 iterator 的值就要加一個 * (例如下面的 s.begin(), s.end())

複雜度:

插入: O(logn)
刪除: O(logn)
搜尋: O(logn)

以下示範 set ,multiset 的用法也都一樣

set <int> s;
multiset <int> ms; 

s.insert(2); // 插入 2
s.insert(3); // 插入 3
s.erase(2); // 刪除 2

cout << *s.begin(); // 輸出 set 的最前面 (最小)因為裡面是排序好的
cout << *(--s.end()); // 輸出最大 要-1 因為 s.end() 不存在,是前一個才是最後一個

auto it = s.lower_bound(2); // 第一個比 2 大的元素 沒找到會回傳 s.end()
cout << *it;
s.erase(it); 

auto it = s.find(2); // 沒找到會回傳 s.end()
cout << *it;

要注意的是 multiset 用 erase 一個值的會把裡面所有的那個值都刪除掉
要只刪除一個的話要用刪 iterator 的方式

multiset <int> ms;
ms.insert(2);
ms.insert(2);
ms.insert(2);

ms.erase(ms.find(2)); // 刪除一個
ms.erase(2); // 刪除全部的 2

queue

一個先進先出 (First in First Out) 的資料結構,很像是一個排隊的結構,先進去的人會先出來。
每次只能取得最前面的元素!不能修改!

複雜度:

插入: O(1)
刪除: O(1)
搜尋: O(n)

queue <int> q; // 宣告裡面存 int 的 queue
queue <pair<int,int> > q2; // 宣告裡面存 pair 的 queue

q.pop(); //移除最前面的元素
q.push(2); // 在最後面加入一個元素
int n = q.size(); // 長度
int f = q.front(); // 隊列最前面的元素

priority_queue

跟 queue 不一樣! 每次可以取得最大值! 也可以自己定義甚麼排序的定義,可以自己寫 overload operator

複雜度:

插入: O(logn)
刪除: O(logn)
搜尋: O(nlogn)

priority_queue <int> pq; // 從大排到小
priority_queue <int, vector<int>, greater<int> > pq2; // 最小值優先的 priority_queue (pq)
int n = pq.size(); // 大小

while(!pq.empty()) { // 當 pq 不是空的
    int x = pq.top(); // pq 的最大值
    pq.pop(); // 移除最大值
    x--;
    if(x) pq.push(x); // 加入 x
}
struct point{
    int x, y;
};

struct cmp {
    bool operator(point a, point b){
        return a.x < b.y;
    }
    // 這個 function 一定要叫做 opeartor 喔
}

int main(){
    priority_queue <point, vector<point>, cmp> pq;
}

要注意的是 priority_queue 判定誰比較優先是判斷 !cmp,所以排序的方法要反過來。
例如你想要最大的優先的話,就應該定義 cmp 是小的優先。

在WordPress.com寫網誌.