STL
Standard Template Library
2023 南11 校 聯合寒訓 - 演算法課程
https://slides.com/d/dVPyJAE/live



-
JasonBigCow 劉哲佑
- 武陵 25th 社長
- 競程 ➡️ 開發
- 深蹲 110 kg
目錄
- STL ?
- vector
- iterator
- pair / tuple
- string
- stack
- queue
- deque
- set
- multiset
- map
- priority_queue
- unordered_map
- bitset
STL Resources
https://en.cppreference.com/w/cpp/container
https://tioj.ck.tp.edu.tw/uploads/attachment/11/40/1.pdf
https://www.geeksforgeeks.org/the-c-standard-template-library-stl/
What is "STL" ?
What is "STL" ?
Standard Template Library
標準模板庫
What is STL ?
C++ 內建的函式庫 ( 在 std 內
提供 模板類別和函數
包括常見的 資料結構 & 演算法
本堂重點:
STL 中的 Container ( 容器類別 )
提供的 資料結構
資料結構
資料結構 ?
{ 用來儲存資料的工具 }
int arr[105];
struct node {
int val;
node *l , *r;
};
// these are data structure !
複雜的題目需要特殊的資料結構來解決!
Review : "Template"
Review : "Template"
C++ 中的 template 可以
創建 泛型函數 和 類別
Function Template
Eg : 要寫一個 通用所有型態 的 swap 函式
Function Template
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
void swap(float& a, float& b) {
float temp = a;
a = b;
b = temp;
}
void swap(char& a, char& b) {
char temp = a;
a = b;
b = temp;
}
int
float
char
. . .
Function Template
template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
char a='a' , b='b';
swap(a,b);
int a=10 , b=99;
swap(a,b);
float a=3.14 , b=9.81;
swap(a,b);
char
int
float
Reusable !
Class Template
那要如何讓 class 也使用多種型態呢?
直接看例子吧!
Class Template
template <class T>
class Board
{
public:
void display(T val) {
cout << val << endl;
}
};
Board<int> IntBoard;
IntBoard.display(10);
Board<char> IntBoard;
IntBoard.display('a');
How to use ?
Class Template
再看另一個跟 STL container 比較像的例子
Class Template
template <class T>
class myArray
{
public:
T get(int idx) {
return ptr[idx];
}
void set(int idx,T val){
ptr[idx] = val;
}
myArray(int size){
ptr = new T[size];
}
private:
T *ptr;
};
Class Template
myArray<int> arrInt(10);
arrInt.set(0,99);
cout<< arrInt.get(0) <<endl;
// result : 99
myArray<float> arrFloat(3);
arrFloat.set(1,3.14);
cout<< arrFloat.get(1) <<endl;
// result : 3.14
int array object
float array object
Note
myArray< block > BlocksArr(10);
// OK
struct block{
uint32_t id;
char level;
double rate;
};
class template 也可以放入自定義的 struct,class
Note
複習完 template 後
接下來的講解會出現 :
T1 T2 T3 ...
a b c ...
分別代表:
a 是 T1 型態
b 是 T2 型態
c 是 T3 型態
...
STL Container Syntax
再介紹容器前
先講一些所有容器 通用的語法 & 規則
STL Container Syntax
containerType<T1> varName();
STL Container Syntax
containerType<T1> varName();
容器型態:
vector / stack /
queue / map ...
填裝型態:
int / float /
struct / class ...
變數命名:
這個容器的 variable name
STL Container Syntax
containerType<T1> varName();
Construct Method ( 建構子 ) :
等一下的 vector 有很多
酷酷的宣告方式!
STL Container Syntax
varName.method();
分成兩個類別 :
1. 取得容器屬性 / 存取資料
2. 對容器進行操作
.size() .empty() .front() .back()
.pop_back() .clear()
vector
「 可以動態調整長度的陣列 」
( 可以像一般陣列 隨機存取 )
vector
Header :
#include<vector>
Construct :
vector<int> vec;
// [ ]
vector<int> vec(3);
// [0,0,0]
vector<int> vec(5,3);
// [3,3,3,3,3]
name(size)
name(size,value)
vector<int> vec={1,2,3};
// [1,2,3]
name = {a,b,c}
vector
Methods :
.size()
.push_back(val)
.pop_back()
.resize(n)
.clear()
.front()
.back()
取得vector長度 在最後插入val 移除最後一個元素 調整vector長度為n 清空vector 查看最前端元素 查看最尾端元素
Description :
Time Complexity :
O(1) O(1) O(1) O(| size − n |) O(size)
O(1)
O(1)
vector
vector<int> a;
for(int i=1;i<=5;i++){
a.push_back(i);
}
// a : [1,2,3,4,5]
for(int i=1;i<=5;i++){
cout<<a[i]<<' '; // 1 2 3 4 5
}
cout<<'\n';
cout<<a.size()<< ' ' << a[a.size()-1] << '\n';
// 5 5
a.pop_back();
cout<<a.size()<<'\n'; // 4
a.clear();
cout<<a.size()<<'\n'; // 0
a.resize(3,9); // a : [9,9,9]
cout<<a.size()<<'\n'; // 3
2D vector
vector<int> g[105];
vector<vector<int>> g(105);
如果只需要決定一維大小的話:
1.
2.
「 在週四的圖論一定會用到 !」
2D vector
vector<int> g[n];
for(int i=0;i<n;i++){
g[i].resize(m);
}
vector<vector<int>> g(n,vector<int>(m));
需要決定兩個維度大小的話:
( 以 n * m 為例 )
1.
2.
vector practice
https://zerojudge.tw/ShowProblem?problemid=f819
Zerojuege f819 圖書館
過期的書開成 vector 來練習吧
vector practice
https://toj.tfcis.org/oj/pro/575/
TOJ 575
這題跟之後圖論「建圖」的操作有點相似 XD
iterator
「 指標有學好,iterator 沒煩惱 」
Iterator
也叫 迭代器 可以當作 STL 容器的 指標 來理解
Iterator Syntax
containerType<T1>::iterator varName;
拿剛剛的 vector 為例:
vector<int>::iterator iter;
如果是 2D vector 的 iterator 呢?
vector<vector<int>>::iterator iter2D;
iterator Syntax
iterator 又醜又長好難記 ...
沒關係!
可以用 auto varName; 就可以了
vector<vector<int>>::iterator iter2D = vec.begin();
auto iter2D = vec.begin();
Note
auto iter2D = vec.begin();
要用 auto 這種精簡寫法的 大前提 !
C++ version 必須是 大於等於 C++11

iterator
取得容器的 iterator :
.begin() .end()
vector<int> a(10,1);
auto iterBegin = a.begin();
auto iterEnd = a.end();
Note
.begin() 是容器的第一個元素
.end() 是容器結尾的後一個位置(無法取值)

STL 容器都是 [ 左閉 右開 )
img ref : https://mropengate.blogspot.com/2015/07/cc-vector-stl.html
iterator Operators
這邊以 iter 代表迭代器
*iter iter++ iter-- iter1 - iter2
- 取得 iter 的值 - 把 iter 向後移一位
- 把 iter 向前移一位
- 得到迭代器之間差幾位
iterator Example
vector<int> a(5);
for(int i=0;i<5;i++){
a[i]=i+1;
}
auto it = a.begin();
cout<< *it <<'\n'; // 1
it++;
cout<< *it <<'\n'; // 2
cout<< *(it+1) << '\n'; // 3;
cout<< *(it-1) << '\n'; // 1;
cout<< (it-a.begin()) << '\n'; // 1
cout<< (a.end()-a.begin()) << '\n'; // 5
Note
vector<int> a(5);
for(int i=0;i<5;i++){
a[i]=i+1;
}
要如何用 iterator 的方式拿到最後一個元素 ?
Error
auto it = a.end();
cout<< *it <<'\n';
是這樣嗎?
Correct
auto it = a.end();
cout<< *(it-1) <<'\n';
要記得 end 是結尾再後一個位置!
iterator
拿到容器的 iterator 可以幹嘛?
回想一下一般的陣列怎麼排序的?
const int n = 10;
int arr[n];
sort(arr,arr+n);
那 vector 要怎麼排序?
vector<int> a(10);
sort(a.begin(),a.end());
剛好傳入的都是 左閉右開
關於更詳細的排序 ( 自定義排序... ) 明天會教到
Note
for(auto it=a.begin();it < a.end();a++){
// ...
}
iterator 不能 比大小
Error
Correct
for(auto it=a.begin();it != a.end();a++){
// ...
}
iterator
用 iterator 跑過 STL 容器
for(auto it=vec.begin(); it!=vec.end() ;it++ ){
// todo
}
還可以更精簡!
iterator
range-base for
for(auto ele : vec){
// todo
}
// 更懶的話:
// 型態可以用 auto
vector<int> a;
for(int x : a){
printf("%d\n" , x );
}
iterate through 2D vector :
vector< vector<int> > mp(10,vector<int>(20,1) );
for(auto i : mp){
for(auto j : i){
cout<<j<<'\n';
}
}
Range-base for
要注意的點!
如果需要修改容器元素:
要記得加上 & (reference)
才能真的修改到元素的值
vector<int> a(3,5);
for(auto i :a){
i=0;
}
for(auto i:a){
cout<<i<<' ';
}
// 5 5 5
vector<int> a(3,5);
for(auto &i :a){
i=0;
}
for(auto i:a){
cout<<i<<' ';
}
// 0 0 0
🤯🤯🤯
✅✅✅
pair
不用自己寫 struct 包裝數對!
題目很常有數對...
pair Syntax
pair< T1 , T2 > varName = make_pair(a,b);
Note :
a 是 T1 型態 b 是 T2 型態
varName.first 可以存取 a varName.second 可以存取 b
pair Syntax
Header :
#include<utility>
Construct :
pair<int,float> a = make_pair(1,2.34);
pair<int,int> b = {1,2};
C++11 up!
兩邊的型態可以不一樣
pair Syntax
access :
.first -取得第一個值
.second -取得第二個值
pair<int,int> p1 = make_pair(3,4);
cout<< p1.first <<' '<< p1.second <<'\n';
// 3 4
p1.first = 5;
cout<< p1.first <<'\n';
// 5
pair
也很常搭配其他 STL 容器使用 !
vector<pair<int,int> > vec;
在排序的時候,會先比較 first 再比較 second
Marco with pair
寫 first , second 好長好麻煩
#define F first
#define S second
cout<< p1.first <<' '<< p1.second<<'\n';
cout<< p1.F <<' '<< p1.S <<'\n';
Marco with pair
#include<bits/stdc++.h>
using namespace std;
#define F first
#define S second;
typedef pair<int,int> pii;
signed main(){
return 0;
}
pair inside pair
pair< int , pair<int,int> > edge;
有三個元素的話:
要怎麼綁成 pair ?
access 1.
access 2.
access 3.
edge.F;
edge.S.F;
edge.S.S;
tuple
有點醜ㄟ
那試試看 tuple ( 數組 )
用 pair 綁 4 個
如果要用 pair 綁 4 個不就更醜
tuple
tuple<T1,T2, ...,Tn> VarName = make_tuple(a,b,...);
Note :
a 是 T1 型態 b 是 T2 型態
...
get<0>(VarName) 可以存取 a get<1>(VarName) 可以存取 b
tuple
auto tp = std::make_tuple(1, "Foo", 3.14);
// index-based access
cout<< get<0>(tp) <<","<< get<1>(tp) <<","<< get<2>(tp) <<'\n';
在排序的時候,與 pair 一樣 越前面的成員順位越高
pair vs tuple
只有 2 個需要綁成一組的時候:
當然用 pair
3 , 4 個需要綁成一組的時候:
看個人喜好
我自己只喜歡用 pair XD
pair practice
https://zerojudge.tw/ShowProblem?problemid=a915
Zerojuege a915 二維點排序
stack
又叫做 堆疊 的資料結構
LIFO
Last In First Out
stack

img ref : https://www.geeksforgeeks.org/stack-data-structure/
stack
Header :
#include<stack>
Construct :
stack<int> stk;
// stack<Type> name;
Methods :
.size()
.push(val)
.pop()
.top()
取得stack長度 新增val到頂端 移除頂端的元素 查看頂端的元素
Description :
Time Complexity :
O(1) O(1) O(1)
O(1)
stack
stack<int> stk;
for(int i=0;i<5;i++) stk.push(i+1);
cout<< stk.top() <<'\n'; // 5
stk.pop();
cout<< stk.top() <<'\n'; // 4
// clear stack
while( stk.size() ){
stk.pop();
}
stack Note
stack 不能 使用 clear()
stack 沒有 iterator
當 stack 是 empty 時:
不能 使用 .top() 和 .pop()
( 不然會 Runtime Error )
stack ?
後序運算
DFS
圖論 Tarjan SCC
stack practice
https://zerojudge.tw/ShowProblem?problemid=b304
Zerojuege b304 Parentheses Balance
可以把「合法」想成「可以消除相對應的括號」
遇到「不合法」就可以先 break
queue
又叫做 佇列 的資料結構
FIFO
First In First Out
queue

img ref : https://www.geeksforgeeks.org/queue-data-structure/
queue
Header :
#include<queue>
Construct :
queue<int> que;
// queue<Type> name;
Methods :
.size()
.push(val)
.pop()
.front()
取得stack長度 新增val到尾端 移除前端的元素 查看前端的元素
Description :
Time Complexity :
O(1) O(1) O(1)
O(1)
queue
queue<int> que;
for(int i=0;i<5;i++) que.push(i+1);
cout<< que.front() <<'\n'; // 1
que.pop();
cout<< que.front() <<'\n'; // 2
// clear queue
while( que.size() ){
que.pop();
}
queue Note
queue 不能 使用 clear()
queue 沒有 iterator
當 queue 是 empty 時:
不能 使用 .top() 和 .pop()
( 不然會 Runtime Error )
queue ?
圖論 BFS
Queue Server
queue practice
等圖論 BFS 就會用到ㄌ
可以嘗試用 class 包裝 vector 實作一個 queue 看看
deque
aka 雙向佇列
「 有人念 deque , 我都念 deque 」
deque
Header :
#include<deque>
Construct :
vector<int> vec;
// deque<Type> name;
Method :
基本上跟 vector 一樣 ( 也可以跟一般陣列一樣隨機存取
.push_front(val)
.pop_front()
新增val到前端 刪除第一個元素
deque Note
基本上跟 vector 一樣 ( 也可以跟一般陣列一樣隨機存取
也有 iterator
也有 .clear()
但是 deque 比 vector 慢很多
deque
deque<int> dq;
for(int i=0;i<5;i++) dq.push_back(i+1);
// 1 2 3 4 5
dq.clear();
cout<< dq.size() <<'\n'; // 0
for(int i=0;i<5;i++) dq.push_front(i+1);
// 5 4 3 2 1
cout<< dq.front() <<'\n'; // 5
dq.pop_front();
cout<< dq[0] <<'\n'; // 4
deque practice
https://zerojudge.tw/ShowProblem?problemid=i400
Zerojuege i400 字串解碼
要先看懂題目第一部分的操作
第二部分用 deque 就很輕鬆ㄌ
Summary
操作的時間複雜度都是
剛剛介紹到的都是 線性資料結構
或
Summary
這些容器的 methods 都很相似
不過最常用到的還是
vector 跟 pair
Next
接下來要介紹的是 非線性資料結構
操作的時間複雜度會出現
Next
非線性資料結構 也是競賽中 最常用到 的資料結構
set , map , priority_queue
multiset , unordered_map
set
集合
「 不會有重複的元素 」
可以快速的 搜尋 , 插入 , 移除 元素
「 不會有重複的元素 」
🙉🙉🙉
set
set 的底層實作 ?
會「動態調整」的 樹狀結構
動態調整 ??
Binary Tree Intro
如果只是一般的 Binary Tree
小 的放 左邊
大 的放 右邊
來看個例子!
Binary Tree Intro
5
10
3
7
2
12
5
10
2
3
7
12
Binary Tree Intro
Binary Tree Intro
如果要找 7
5
10
3
7
2
12
走 2 步就找到了
Binary Tree Intro
看起來沒什麼問題ㄚ
5
10
3
7
2
12
再來看一個例子:
Binary Tree Intro
5
10
3
11
13
15
5
10
13
3
11
15
Binary Tree Intro
可以看到
在連續插入單調的元素時:
搜尋的時間複雜度
會從
退化成
RB Tree
為了解決 退化 的問題
set 是用 Red-Black Tree 實作的
可以保持樹整體的 平衡性
RB Tree
img ref : https://www.geeksforgeeks.org/introduction-to-red-black-tree/

set
Header :
#include<set>
Construct :
set<int> st;
與之前介紹的 vector 一樣的 Methods :
.size()
.empty()
.clear()
取得 set 長度 回傳 set 是否為空 清空 set
O(1)
O(1)
O(n)
與之前介紹的 vector 一樣有 iterator
set
.begin()
.end()
set 開頭 set 結尾後一個
與之前介紹的 vector 一樣有 iterator
.begin() 到 .end() 預設為 由小到大
set
set 自己的 Methods :
.insert(val) .count(val) .find(val) .erase(val) .erase(iter)
插入 val 回傳 val 個數 回傳 val 所在的 iterator「val不在則回傳 set.end() 」刪除 val 刪除該 iterator
set
set 自己的 Methods :
.upper_bound(val) .lower_bound(val)
: 在 set 中找到第一個指向元素 ≥ val 的迭代器
: 在 set 中找到第一個指向元素 > val 的迭代器
明天的 sort & searching 會再細講
set Note
因為 set 的 記憶體 位置 不連續 :
在 set 插入多個重複的元素的話:
在 set 內也只會有一個!
iterator 無法相減
set
set<int> st;
for(int i=5;i>=1;i--) st.insert(i);
for(auto it=st.begin();it!=st.end();it++){
cout<< *it <<'\n';
} // 1 2 3 4 5
for(int i=1;i<=6;i++) st.insert(i);
for(auto it=st.begin();it!=st.end();it++){
cout<< *it <<'\n';
} // 1 2 3 4 5 6
for(auto i : st ){
cout<< i <<'\n';
}// same as above
// 1 2 3 4 5 6
check val in set
// using find
if( st.find(val) == st.end() ){
printf("Not Found\n");
}
else{
printf("%d is in set\n",val);
}
// using count
if( st.count(val)) ){
printf("%d is in set\n",val);
}
else{
printf("Not Found\n");
}
get min/max in set
// get min element in set
cout<< *st.begin() <<'\n';
// get max element in set
cout<< *(--st.end()) <<'\n';
erase min/max in set
// erase min element in set
st.erase( st.begin() );
// erase max element in set
st.erase( (--st.end()) );
set practice
https://cses.fi/problemset/task/1621
CSES Distinct Numbers
set 的裸題 !
set practice
https://zerojudge.tw/ShowProblem?problemid=f607
Zerojuege f607 切割費用
沒錯,可以用 set 解!
提示 2:會用到 iterator
提示 1:可以先把邊界條件加入 set
multiset
多重集合
跟 set 非常像
「 允許重複的元素 」
multiset
Header :
#include<set>
Construct :
multiset<int> st;
set , multiset 都是在同一個 header !
Methods 也都跟 set 一樣 !
不過有些 差異
multiset vs set
.count(val) 的時間複雜度是:
erase in multiset
.erase(val) : 會刪除所有的 val元素
erase in multiset
那如果只想刪除 一個val元素 呢
先使用 .find(val) 拿到某個val元素的 iterator
再透過 .erase(iter) 達到只刪除一個val元素的操作
erase in multiset
multiset<int> ms;
for(int i=1;i<=10;i++) ms.insert(1);
cout<< ms.size() <<' '<< ms.count(1) <<'\n'; // 10 10
ms.erase( s.find(1) );
// only delete one element equals 1
cout<< ms.size() <<' '<< ms.count(1) <<'\n'; // 9 9
ms.erase(1);
cout<< ms.size() <<' '<< ms.count(1) <<'\n'; // 0 0
map
映射
「 其他語言的 dictionary , 就是 STL 的 map 」
沒有重複的 key-value pair
map
map 的底層實作 ?
跟 set 一樣,也是 動態平衡的樹狀結構
搜尋 , 插入 , 移除 元素
map
Header :
#include<map>
Construct :
map<string,int> mp;
// map<T1,T2> name;
T1 是 key 的型態 , T2 是 val 的型態
access :
mp["a"] = 26;
cout<< mp["a"] ;// 26
map
STL通用的 Methods :
.size()
.empty()
.clear()
.erase(key) .erase(iter) .find(key) .lower_bound(key) .upper_bound(key)
與set相似的 Methods :
map
map<string,int> m1;
m1["jason"]=18;
map<string,string> m2;
m2["jason"]="BigCow"
map<int,int> m3;
m3[-10] = 24;
cout<< m1["jason"] <<' '<<m2["jason"] <<'\n';
// 18 BigCow
cout<< m3[-10] <<' '<< m3[20]<<'\n';
// 24 0
default value
check index of map
跟 set 一樣用 .count(idx) 或 .find(key)
// using find
if( mp.find(key) == mp.end() ){
printf("Not Found\n");
}
else{
printf("mp[%d] = %d\n",key,mp[key]);
}
// using count
if( mp.count(key)) ){
printf("mp[%d] = %d\n",key,mp[key]);
}
else{
printf("Not Found\n");
}
iterator of map
map 其實是由 pair 組成的結構
所以 iterator 指向的是一個 pair
需要用 iter->first , iter->second
分別來取得 key 與 value
也可以用用 (*iter).first 或 (*iter).second
( 與 structure pointer 取值概念一樣 )
iterate through map
.begin()到.end()是按照 key 由小到大
map<int,int> mp;
for(int i=1;i<=5;i++) mp[i] = i*10;
for(auto it=mp.begin();it!=mp.end();it++){
cout<< it->first <<' '<< it->second<<'\n';
// (*it).first (*it).second
}
/* 1 10
2 20
3 30 ... */
for(auto i : mp){
cout<< i.first <<' '<< i.second <<'\n';
}
// same as above
map practice
https://cses.fi/problemset/task/1640
CSES Sum of Two Values
提示1: target 可以想成 current + x
提示2: 那 x 就是 target - current
set 也可以搞定,不過來練習一下 map 吧
priority_queue
優先隊列
在其他語言都叫 Heap
STL 中的 priority_queue 預設是 Max-Heap
Heap Intro
也是一個 樹狀結構
跟一般的 Binary Tree 不同
Heap 會保持為 Complete Binary Tree
Heap Intro
以下都以 Max-Heap 來講解
父節點 大於 子節點
性質:
Heap Intro
會保持像這樣,不會某一邊太重
Complete Binary Tree
Heap Intro
99
10
9
55
6
20
5
父節點 大於 子節點
20 大於 10 ㄟ
沒有違反性質 👌的
Heap Intro
99
10
9
55
6
20
5
get Max element
Heap Intro
99
10
9
55
6
20
5
remove Max element
Heap Intro
10
9
55
6
20
5
remove Max element
Heap Intro
add new element
99
10
9
55
6
20
5
100
100
Heap Intro
add new element
99
10
9
55
6
20
5
100
100
55
100
99
priority_queue
Header :
#include<queue>
Construct :
priority_queue<int> pq;
// priority_queue<T> name;
Methods :
.size()
.empty()
.push(val) .pop() .top()
min priority_queue
pq 預設是大到小
要如何改成小到大 ?
priority_queue<int,vector<int>,greater<int>> min_pq;
// priority_queue<Tp,vector<Tp>,greater<Tp>> name;
priority_queue
priority_queue<int> max_pq;
priority_queue<int,vector<int>,greater<int>> min_pq;
for(int i=1;i<=5;i++){
max_pq.push(i);
min_pq.push(i);
}
cout<< max_pq.top() <<' '<< min_pq.top() <<'\n';
// 5 1
max_pq.pop();
min_pq.pop();
cout<< max_pq.top() <<' '<< min_pq.top() <<'\n';
// 4 2
priority_queue practice
https://leetcode.com/problems/kth-largest-element-in-an-array/
LeetCode kth-largest-element-in-an-array
using priority_queue
priority_queue practice
https://cses.fi/problemset/task/1076
CSES Sliding Median
不小心偷渡 sliding window ㄌ
暴力解: 對新的序列都 sort 一遍
顯然會 TLE ㄉ
priority_queue practice
https://cses.fi/problemset/task/1076
CSES Sliding Median
把序列切成兩半後
前半序列中的最大值
後半序列中的最小值
提示: 要維護好序列的中間
中位數可以看成
所以可以開兩個 PQ 來維護
priority_queue practice
https://cses.fi/problemset/task/1076
CSES Sliding Median
重點:要維護好兩邊 PQ 的長度!
前半太多,放在後半
後半太多,放在前半
超出當前的 window 時要移除
unordered_set unordered_map
但是不一定會比 RB-Tree 的 set/map 還快
unordered_set/map
原理:
透過 Hash 讓 搜尋 插入 刪除 更快
但是 Hash 有 碰撞 的風險
( 兩個數字 hash 的結果一樣 )
很容易會被 卡測資 導致 TLE
unordered_set/map
因為是透過 Hash:
沒有
.upper_bound .lower_bound
剩下的用法都跟 set/map 一樣
Header :
#include<unordered_set>
#include<unordered_map>
bitset
用 bit 就夠,為什麼要 byte
壓常的好東西
bit vs byte
C++ 中的 bool 大小其實是 1 Byte
也就是用:
00000000
00000001
來表示 true
來表示 false
前 7 個 bit 都被讓廢掉了
bitset
可以看成是一個 優化過的 bool 陣列
可以對 同大小 的 bitset 做 位元運算
bitset
Header :
#include<bitset>
Construct :
bitset<1005> b;
// bitset<SIZE> name;
中間是放大小 !
b[i] = 1;
b[i+1] = 0;
cout<< b[i] <<'\n';
跟一般 bool 陣列一樣
bitset
Methods :
.count() .set() .reset() .flip() .to_string() .to_ulong() b1 (位元運算) b2
回傳有幾個 1 將所有位元設為 1 將所有位元設為 0 將所有位元反轉 轉為字串 轉為 unsigned long 將 b1、b2 做位元運算
Description :
Time Complexity :
Summary
多練習,多寫題!
STL 東西好多 ...
STL 在競賽中是很基本的資料結構
學完 STL 後還有
PBDS
Binary Index Tree
Segment Tree
這些酷東西可以學
practice solution
https://hackmd.io/@jasonliu424/B1-HBPbno
contact me
Github⚙️ https://github.com/jason810496 FB 🧬 https://www.facebook.com/JasonBigCow IG 🐮 https://www.instagram.com/jason2004424/
有地方沒講清楚歡迎來問我 > <
C++ STL Container
By jasonliu424
C++ STL Container
C++ STL Container
- 458