--- ###### tags: `sprout` --- # STL Container *slide: https://hackmd.io/@htting/HksIP5wiI#/* *slido: 99601* *2020/6/6 丁緒慈* --- ## 資料結構 *你會怎麼儲存這些資料* ![](https://i.imgur.com/6Nk2W3t.png) ![](https://i.imgur.com/ywGLHPc.png) ![](https://i.imgur.com/ta42yOB.png) ---- 電腦中儲存、組織資料的方式,就成為資料結構 ![](https://i.imgur.com/VMa2TrJ.png) ---- *等等...那 STL 又是甚麼* - Standard Template Library - 包含資料結構與演算法的模板 -> 不用慢慢刻啦 --- ## Queue ![](https://i.imgur.com/ywGLHPc.png) 跟排隊一樣,先進先出(First In First Out) - 把東西塞進去的動作叫做 enqueue - 把東西拿出來的動作叫做 dequeue ---- ### [函式庫](http://www.cplusplus.com/reference/queue/queue/) *使用前記得 #includle <queue>* ```cpp std::queue<T> myqueue // 宣告 myqueue.push(val); // 加入元素(不能插隊,只能放在尾端) myqueue.pop(); // 刪除元素(讓排頭離開隊伍,只能刪除頭) ``` T 可以是任何資料型態 (int、char、自己寫的 struct、STL container) 注意:對空的 queue pop 會噴錯 ---- ### [函式庫](http://www.cplusplus.com/reference/queue/queue/) ```cpp std::queue<T> myqueue // 宣告 myqueue.push(val); // 加入元素(不能插隊,只能放在尾端) myqueue.pop(); // 刪除元素(讓排頭離開隊伍,只能刪除頭) T f = myqueue.front(); // 看看第一個元素 T b = myqueue.back(); // 看看最後一個元素 bool emp = myqueue.empty(); // 是空的嗎? int size = myqueue.size(); // 有幾個元素? ``` 這些都是O(1)操作 ---- ### Example 想想看會輸出甚麼 ```cpp= #include <iostream> #include <queue> int main() { std::queue<int> myqueue; myqueue.push(0); myqueue.push(1); myqueue.push(2); myqueue.pop(); myqueue.push(3); myqueue.pop(); std::cout << "first element = " << myqueue.front() << "\n"; std::cout << "last element = " << myqueue.back() << "\n"; std::cout << "#element = " << myqueue.size() << "\n"; } ``` ---- ### Example Answer ```cpp myqueue.push(0); // 0 myqueue.push(1); // 0 1 myqueue.push(2); // 0 1 2 myqueue.pop(); // 1 2 myqueue.push(3); // 1 2 3 myqueue.pop(); // 2 3 ``` first element = 2 last element = 3 #element = 2 ---- ### 課堂練習 [Neoj 37 Queue 練習](https://neoj.sprout.tw/problem/37/) --- ## Stack ![](https://i.imgur.com/ta42yOB.png) 如果要你拿一本書,你會拿哪一本 如果要你把一本書放到這堆裡面,你會放在哪裡 後進先出的資料型態(Last In First Out) ---- ### [函式庫](http://www.cplusplus.com/reference/stack/stack/) *使用前記得 #includle <stack>* ```cpp std::stack<T> mystack // 宣告 mystack.push(val); // 加入元素(把書放在最上面,只能放在尾) mystack.pop(); // 刪除元素(拿走最上面的一本書,只能刪除尾) T t = mystack.top(); // 看看最後一個元素 bool emp = mystack.empty(); // 是空的嗎? int size = mystack.size(); // 有幾個元素? ``` T 可以是任何資料型態 這些都是O(1)操作 ---- ### Example 想想看會輸出甚麼 ```cpp= #include <iostream> #include <stack> int main() { std::stack<int> mystack; mystack.push(0); mystack.push(1); mystack.push(2); mystack.pop(); mystack.push(3); mystack.pop(); std::cout << "last element = " << mystack.top() << "\n"; std::cout << "#element = " << mystack.size() << "\n"; } ``` ---- ### Example Answer ```cpp mystack.push(0); // 0 mystack.push(1); // 0 1 mystack.push(2); // 0 1 2 mystack.pop(); // 0 1 mystack.push(3); // 0 1 3 mystack.pop(); // 0 1 ``` last element = 1 #element = 2 ---- ### 課堂練習 [Neoj 36 Stack 練習](https://neoj.sprout.tw/problem/36/) --- ## Deque - 念作 deck - Double-Ended QUEue - 小孩子才做選擇,我全都要 ![](https://i.imgur.com/G1onMVp.png) ---- ### [函式庫](http://www.cplusplus.com/reference/deque/deque/) *使用前記得 #includle <deque>* ```cpp std::deque<T> mydeque; // 宣告 mydeque.push_back(val); // 把資料放在最後面 mydeque.push_front(val); // 把資料放在最前面 mydeque.pop_back(); // 刪除最後面的資料 mydeque.pop_front(); // 刪除最前面的資料 T f = mydeque.front(); // 查看最前面的資料 T b = mydeque.back(); // 查看最後面的資料 bool emp = mydeque.empty(); // 是空的嗎? int size = mydeque.size(); // 有幾個元素 ``` T 可以是任何資料型態 這些都是O(1)操作 ---- ### Example 想想看會輸出甚麼 ```cpp #include <iostream> #include <string> #include <deque> using namespace std; struct student { int id; string name; student(int _id, string _name) { id = _id; name = _name; } }; int main() { deque<student> s; s.push_back(student(15, "Alice")); s.push_front(student(23, "Bob")); s.push_front(student(32, "Carol")); std::cout << s.back().name << "\n"; s.pop_back(); std::cout << s.front().name << "\n"; s.pop_front(); std::cout << s.back().name << "\n"; } ``` ---- ### Example Answer ```cpp s.push_back(student(15, "Alice")); // {15, Alice} s.push_front(student(23, "Bob")); // {23, Bob} {15, Alice} s.push_front(student(32, "Carol")); // {32, Carol} {23, Bob} {15, Alice} std::cout << s.back().name << "\n"; s.pop_back(); // {32, Carol} {23, Bob} std::cout << s.front().name << "\n"; s.pop_front(); // {23, Bob} std::cout << s.back().name << "\n"; ``` --- ## Vector ```cpp #include <iostream> int main() { int n; std::cin >> n; int arr[n] = {}; // WRONG!!! } ``` ```cpp #include <iostream> int main() { int n; int arr[1000000000] = {}; // 沒有更好的方法嗎 } ``` ---- ### Dynamic Array ![](https://i.imgur.com/WcQOvQ9.png =400x508) 空間滿了再擴充到兩倍 ---- ### Vector - 就是一種 Dynamic Array - 宣告 ```cpp std::vector<T> mv1; // 空的vector std::vector<T> mv2(n); // 放n個東西 std::vector<T> mv3(n,val); // 放n個val ``` ---- ### [函式庫](http://www.cplusplus.com/reference/vector/vector/) *使用前記得 #includle <vector>* ```cpp std::vector<T> mv mv.push_back(val); // 把資料放在最後面 mv.pop_back(); // 刪除最後面的資料 bool emp = mv.empty(); // 是空的嗎 int size = mv.size(); // 有幾個元素 ``` ---- ### Example 想想看會輸出甚麼 ```cpp #include <iostream> #include <vector> using namespace std; int main() { vector<int> mv; for(int i = 0; i<5; ++i) mv.push_back(i); mv[3] = 100; // 就像陣列 mv.pop_back(); for(int i = 0; i<mv.size(); ++i) cout << mv[i] << " "; } ``` ---- ### Example Answer ```cpp #include <iostream> #include <vector> using namespace std; int main() { vector<int> mv; for(int i = 0; i<5; ++i) mv.push_back(i); // 0 1 2 3 4 mv[3] = 100; // 0 1 2 100 4 mv.pop_back(); // 0 1 2 100 for(int i = 0; i<mv.size(); ++i) cout << mv[i] << " "; } ``` 0 1 2 100 ---- 如果要對 Vector 中間的元素做操作呢? 例如 刪除中間的元素、在中間插入元素 --- ## Iterator - 迭代器 - 可以想成 STL 的指標 ---- ### Recall - 宣告一個指標 ptr - int *ptr; - double *ptr; - int arr[10] - 開頭指標:arr / 結尾指標:arr + 10 - 看看指標指向甚麼 - *ptr - 變成下一個 pointer - ptr++ ---- ### Vector & Iterator - 宣告 - vector<int>::iterator iter - vector<int> mv - 開頭指標:mv.begin() - 結尾指標:mv.end() - 看看 iterator 指向甚麼 - *iter - 變成下一個 iterator - iter++ ---- ### Vector & Iterator ![](https://i.imgur.com/vr52h9h.jpg) ---- ### 遍歷所有元素 ![](https://i.imgur.com/vr52h9h.jpg) ```cpp vector<int>::iterator iter; for(iter = mv.begin(); iter!=mv.end(); iter++) cout << *iter << " "; ``` ---- ### 插入 & 刪除 ![](https://i.imgur.com/vr52h9h.jpg) ```cpp mv.insert(mv.begin()+2, 3); mv.erase(mv.begin()+1); ``` ---- ### auto ```cpp vector<int>::iterator iter = mv.begin(); auto iter = mv.begin(); ``` - 一般的變數不會使用 - 有正確的型別概念才可以使用 ---- ### auto ![](https://i.imgur.com/vr52h9h.jpg) ```cpp for(auto iter = mv.begin(); iter != mv.end(); iter++) cout << *iter << " "; ``` ---- ### Range-based For ```cpp for(auto i : mv) cout << i << " "; ``` ---- ### 注意! 會輸出幾個'#' ```cpp vector<int> v(10); for(auto i = v.size() ; i>=0 ; i--){ cout << '#'; } ``` --- ## List - double linked-list ![](https://i.imgur.com/cO1WvNX.png) ---- ### [函式庫](http://www.cplusplus.com/reference/list/list/) *使用前記得 #includle <list>* ```cpp std::list<T> mylist // 宣告 mylist.push_front(val); // 把資料放在最前面 mylist.push_back(val); // 把資料放在最後面 mylist.pop_front(); // 刪除最前面的資料 mylist.pop_back(); // 刪除最後面的資料 std::list<T>::iterator it1 = mylist.begin(); std::list<T>::iterator it2 = mylist.end(); mylist.insert(it, val); mylist.erase(it); ``` 注意:list 的 iterator 可以 ++、-- 但不能 +=k ---- ![](https://i.imgur.com/yCc0KeC.jpg) ---- ### Example ![](https://i.imgur.com/efINfEC.jpg) ```cpp std::list<int> mylist; for(int i = 0; i<5; ++i) mylist.push_back(i); for(auto i : mylist) cout << i << " "; cout << "\n"; ``` ---- ### erase ![](https://i.imgur.com/IBgLkV9.jpg) ```cpp // 刪除 3 auto to_delete = mylist.begin(); for(int i = 0; i<3; ++i) to_delete++; mylist.erase(to_delete); for(auto i : mylist) cout << i << " "; cout << "\n"; ``` ---- ### insert ![](https://i.imgur.com/GIst37i.jpg) ```cpp // 把 5 插入在 2 之前 auto to_insert = mylist.begin(); for(int i = 0; i<2; ++i) to_insert++; mylist.insert(to_insert, 5); for(auto i : mylist) cout << i << " "; cout << "\n"; ``` ---- 感覺 list 可以取代 stack, queue, deque和vector??? ---- 雖然 list 包含了很多好用的函式庫 但代價是速度很慢
{"metaMigratedAt":"2023-06-15T08:38:38.298Z","metaMigratedFrom":"Content","title":"STL Container","breaks":true,"contributors":"[{\"id\":\"af982bdb-64aa-4193-8aa9-59531d66033e\",\"add\":10874,\"del\":2376}]"}
    704 views