演算法 [2]

基礎 STL

INFOR38 學術 葉倚誠

課程大綱

#1 標準模板庫 (STL)
#2 容器 Container/適配器 Adapter
#3 迭代器 iterator
#4 演算法 Algorithms
#5 Pair/字串 String

概述

標準模板庫 (STL)

  • C++ 標準函式庫的一部分
  • 內建各式資料結構/演算法
  • 支援多數 OJ 及競賽
  • 容器/迭代器/演算法
  • cppreference.com

容器 Container / 適配器 Adapter

容器/適配器

容器:用來儲存資料的結構

順序容器:array、vector、list、deque

關聯容器:set、map

無序容器:unorderd_set、unorderd_map

適配器:類似容器,但沒有迭代器

queue、priority_queue、stack

順序容器

Sequence Container

Vector

Deque

List

Array

Array 陣列

#include <array>
array<int, 5> a = {1, 2, 3, 4, 5};
operator[] / at() 存取指定索引值元素
front() / back() 存取第一個/最後一個元素
fill() 填充指定元素在容器中
empty() 回傳容器是否為空
size() 回傳容器長度

Vector 動態陣列

#include <vector>
vector<int> v = {1, 2, 3, 4, 5}
operator[] / at() 存取指定索引值元素
front() / back() 存取第一個/最後一個元素
push_back() / pop_back() 在容器末端插入/刪除元素
clear() 清空容器
empty() 回傳容器是否為空
size() 回傳容器長度
resize() 改變容器長度

Deque 雙向隊列

#include <deque>
deque<int> d = {1, 2, 3, 4, 5}
operator[] / at() 存取指定索引值元素
front() / back() 存取第一個/最後一個元素
push_back() / pop_back() 在容器末端插入/刪除元素
push_front() / pop_front() 在容器頭端插入/刪除元素
clear() 清空容器
empty() 回傳容器是否為空
size() 回傳容器長度
resize() 改變容器長度

List 雙向鏈表

#include <list>
list<int> l = {1, 2, 3, 4, 5}
empty() 回傳容器是否為空
size() 回傳容器長度
resize() 改變容器長度
  • 絕大多數功能與 deque 一樣,支援雙向插入
  • 資料不存在連續記憶體中,無法使用下標

關聯容器

Associative Container

Map

Set

multiset

multimap

Set

  • #include <set>
  • set<T> s;

  • insert(it, x) / erase(x / it)

  • find(x) / count(x)

  • size()

  • empty() / clear()

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    set<int> s;

    for (int i = 0; i < 10; ++i) s.insert(i);
    for (int i = 0; i < 10; ++i) s.insert(i);
    for (auto it = s.begin(); it != s.end(); it++) {
        cout << *it << " ";
    } // 0 1 ... 9
    cout << endl;
    cout << s.size() << endl; // 10
    cout << s.count(5) << endl; // 1

    return 0;
}

元素自動排序 / 不允許重複元素

Map

  • #include <map>
  • map<T, T> m;

  • insert({key, val}) / erase(key / it)

  • find(key) / count(key)

  • size()

  • empty() / clear()

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    map<string, int> m;
    
    m["a"] = 1;
    m["b"] = 2;
    m["c"] = 3;
    m.insert({"d", 4});

    cout << m.count("a") << endl; // 1
    cout << (m.find("a") != m.end()) << endl; // 1

    return 0;
}

按鍵值自動排序 / 不允許重複鍵值

適配器

Adapter

Stack

priority_queue

Queue

Queue

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    queue<int> q;

    for (int i = 1; i <= 5; ++i) q.push(i);
    while (!q.empty()) { // 1 2 3 4 5
        cout << q.front() << " ";
        q.pop();
    }
    cout << endl;

    return 0;
}
  • #include <queue>
  • queue<T> q;

  • push(x) / pop()

  • front() / back()

  • size() / empty()

  1. Deque 為底層容器

  2. 先進先出

Priority Queue

  • #include <priority_queue>
  • priority_queue<T, Container, Compare> pq

  • push(x) / pop()

  • top()

  • size() / empty()

  1. 自訂底層容器

  2. 自訂比較函數

  3. 按照優先級排序

Stack

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    stack<int> s;

    for (int i = 0; i < 10; i++) s.push(i);
    while (!s.empty()) { // 9 8 7 6 5 4 3 2 1 0
        cout << s.top() << " ";
        s.pop();
    }
    cout << endl;

    return 0;
}
  • #include <stack>
  • stack<T> s;

  • push(x) / pop()

  • top()

  • size() / empty()

  1. Deque 為底層容器

  2. 後進先出

迭代器 iterator

單向迭代器 ForwardIterator 僅能向前遍歷容器
雙向迭代器 BidirectionalIterator 可以向前 / 後遍歷容器
隨機存取迭代器 RandomAccessIterator 可以任意訪問整個容器

迭代器是什麼?

  • 用來遍歷容器中的元素
  • 類似一個 STL 專用的指標
  • 代表指定的記憶體位址
  • 使用 *it 存取元素

迭代器分類

● 前向迭代器:

unorded_set, unorded_multiset, unorded_map, unorded_multiset

雙向迭代器:

list, set, multiset, map, multimap

隨機存取迭代器

array、vector、deque

無迭代器 (非容器)

queue、priority_queue、stack、pair

演算法 Algorithm

演算法是什麼?

  • STL 內建的一些函數

  • 方便執行常用的操作

  • 所以不用再自己寫

Sort

#include <bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
	vector<int> v(n);
    
    for (int i=0;i<n;i++) {
    	cin >> v[i];
    }
    
    sort(v.begin(),v.end());
    
    for (int i=0;i<n;i++) {
    	cout << v[i] << ' ';
    }
}

Sort

#include <bits/stdc++.h>
using namespace std;

bool cmp(int a ,int b) {
	return a < b; // 原本從小到大,變成從大到小
}


int main() {
    int n;
    cin >> n;
	vector<int> v(n);
    
    for (int i=0;i<n;i++) {
    	cin >> v[i];
    }
    
    sort(v.begin(), v.end(), cmp);
    
    for (int i=0;i<n;i++) {
    	cout << v[i] << ' ';
    }
}

Reverse

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    vector<int> v = {5, 1, 3, 4, 2};

    for (int i : v) cout << i << " ";
    cout << endl;
    // 5 1 3 4 2
    
    reverse(v.begin(), v.end());
    for (int i : v) cout << i << " ";
    cout << endl;
    // 2 4 3 1 5

    return 0;
}

Count

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    vector<int> v = {1, 1, 2, 3, 3, 4, 6, 7, 7, 7};

    cout << count(v.begin(), v.end(), 7) << endl;  // 3
    cout << count(v.begin(), v.end(), 1) << endl;  // 2
    cout << count(v.begin(), v.end(), 8) << endl;  // 0

    return 0;
}

Min / Max

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    cout << min(10, 5) << endl;        // 5
    cout << max(10, 5) << endl;        // 10
    cout << min({10, 5, 20}) << endl;  // 5
    cout << max({10, 5, 20}) << endl;  // 20

    return 0;
}

Find

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};

    if (find(v.begin(), v.end(), 3) != v.end()) cout << "Yes" << endl;
    else cout << "No" << endl; // Yes
    
    if (find(v.begin(), v.end(), 6) != v.end()) cout << "Yes" << endl;
    else cout << "No" << endl; // No

    return 0;
}

Remove

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};

    v.erase(remove(v.begin(), v.end(), 3), v.end());
    for (const auto &i : v) cout << i << " ";
    cout << endl;
    // 1 2 4 5
    

    return 0;
}

Transform

#include <bits/stdc++.h>
#define endl '\n'

using namespace std;

int f(const int &x) { return x * 2; }

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    string s = "HeLlo woLRD";

    transform(v.begin(), v.end(), v.begin(), f);
    for (const auto &i : v) cout << i << " "; 
    cout << endl;
    // 2 4 6 8 10
    
    transform(s.begin(), s.end(), s.begin(), ::tolower);
    cout << s << endl;
    // hello world

    return 0;
}

The End

演算法[2] 基礎 STL

By Ethan Yeh

演算法[2] 基礎 STL

  • 113