STL

presented by

125 4,16,28

預防針

名詞能量高,請小心服用

見到 綠字,代表不用特別記得的名詞,

只要大概知道概念就好

Basic STL

What are STLs?

Standard Template Library

useful built-in tools

Four Parts Of STL

  • containers 容器
  • adapters 適配器

 

  • iterator 迭代器

 

  • algorithm 演算法

聽起來好難

都是裝東西的“東西”

常見容器/適配器

反正就是常見的裝東西的東東(資料結構

vector

deque

list (linked list)

set (or multiset)

map (or multmap)

...

stack

queue

...

前情提要

物件 (Object)

喔不,聽起來很可怕?

其實定義很簡單,就是你想的"Object"

問題來了

誰是一個物件

簡單來

物件要可以「丟」

=

如果東西不能丟?
把它包裝起來!

問題來了

誰是一個物件

來比較一下

C - style array

std::vector

int A[3] = {0,1,2}
int B[3];
B = A; // 不合法
vector<int> C = {0,1,2};
vector<int> D;
D = C; // 合法
void foo(int arr[]) {
    cout << "function\n";
}
// 呼叫時
int arr[];
foo(arr); // 只用指標傳遞
void foo(vector<int> arr) {
    cout << "function\n";
}
// 呼叫時
vector<int>arr;
foo(arr); // 直接傳遞

所以,STL為什麼重要

  • 把許多東西物件化!
  • 提供好用的成員函數

這又是啥?

成員

包裝完的物件,會有許多功能

取用方式?用眼睛看

object.member_name

栗子

Student 陳彥臻;

cout << 陳彥臻.height << endl;

那成員函數勒?

for (int i = 0; i < INF; ++i) {

    陳彥臻.AfraidOfWater()

}

STL 常見成員函數

.empty()

.size()

.clear()

 

.pop_back()

.push_back()

.pop_front()

.push_front()

.insert()

.erase()

.front()

.back()

.top()

 

.begin()

.end()

 

.find()

.......

回傳iterator

Iterator

迭代器

Iterator是什麼

進化版的指標

用法跟指標差不多

那為什麼需要多一個東西呢?

index 0 1 2 3
value 12 23 10 35

以vector為例

vector <int> water = {12, 23, 10, 35};

water.begin()

water.end()

water.front() == 12

water.back() == 35

vector<int>::iterator it = water.begin()
auto it2 = water.begin()

以set為例

orz.begin()

orz.end()

orz.end()-1

因為記憶體不連續,所以需要用iterator這種特別的東東

it++

還是看不懂?

Vector

容器之王

Vector是甚麼?

其實就是陣列

可以伸縮自如的那種

如果是Array

宣告時就要有大小了

例如:arr[10]

但vector沒在跟你管這些的啦

直接伸縮

by 建電一二學術長檸檬

宣告

vector<型態> 名字;

vector<型態> 名字(大小,值);

vector<型態> 名字 = {2,3,4};

vector<float> foo;
vector<int> bar(30); // 30個0
vector<int> water(10,-1); // 填十個-1
vector<string> dian = {"Brine", "Che", "Willy"};

取值,改值

時間複雜度 O(1)

water[0] = 16;
cout << water[0] << endl;

push_back

在後面插入一個東東

時間複雜度 O(1)

vector <int> water;
for (int i = 0; i < 10; ++i) {
    water.push_back(i*i);
}
for (int i = 0; i < 10; ++i) {
    cout << water[i] << " ";
}
OUTPUT: 
0 1 4 9 16 25 36 49 64 81

pop_back

把最後面一個東東丟掉

時間複雜度 O(1)

vector <int> water = {1,2,3,4,5};
water.pop_back();
cout << "size: " << water.size() << endl;
for (int i = 0; i < water.size(); ++i) {
    cout << water[i] << endl;
}
OUTPUT: 
size: 4
1 2 3 4

如果不是在最後面插入勒?

vector沒有pop_front(), push_front()

用insert(), erase()

O(n)!!!

.empty()

陣列為空?

時間複雜度 O(1)

回傳bool

vector<int> v;
v.push_back(5);
if(v.empty()){
  cout << "empty!\n";
} else {
  cout << "not empty!\n"
}
//輸出 "not empty!"

.size()

陣列大小

時間複雜度 O(1)

回傳 size_t (aka long)

vector<int> v;
v.push_back(5); 
v.push_back(7); 
v.pop_back();     // 7被移出去
cou t<< v.size(); // 1
v.pop_back();     // 5被移出去
cout << v.size(); // 0

跑過整個vector

how?

1. 一般for迴圈

vector <int> water = {1,2,5,16};
for (int i = 0; i < water.size(); ++i) {
    cout << water[i] << " ";
}

跑過整個vector

how?

2. 迭代器

vector <int> water = {1,2,5,16};
for (auto it = water.begin(); it != water.end; it++) {
    cout << *it << " ";
}

跑過整個vector

how?

3. for range

vector <int> water = {1,2,5,16};
for (auto item : water) {
    cout << item << " ";
}

剛剛只大致介紹一下

code有空自己再去看

Deque

雙頭龍

做簡報好累

vector只能push屁股好討厭?

用deque!

push_back()  pop_back()
push_front()  pop_front()

通通O(1)

deque <string> water = {"Hong-An", "is", "so", "dian"};
water.pop_front(); // {"is", "so", "dian"};
water.pop_back();  // {"is", "so"}; 
water.push_front("AaW"); // {"AaW", "is", "so"}
water.push_back("week"); // {"AaW", "is", "so", "week"}

缺點,常數大

但也蠻好用的

List

串列
做簡報好累

反正就是一個長這樣的東西

插入刪除O(1)

查東西O(n)

可以用來插隊

插入O(1) !!!

Stack

來玩疊疊樂摟
鄭竣陽aka資訊社學術長 好像也講過

是一個adapter

內部容器要有 empty、size、back、push_back、 pop_back 這些函式

stack<int> a; // 預設用vector
stack<int, vector<int>> b;
stack<int, deque<int>> c;
stack<int, list<int>> d;

LIFO aka last in first out

4
3
2
1

pop() push()

top()

範例

#include <iostream>
#include <stack>
using namespace std;
int main() {
	stack<int> iamweek;
	iamweek.push(1);
	iamweek.push(2);
	cout << iamweek.top() << endl; // 2
	iamweek.pop();
	cout << iamweek.top() << endl; // 1
	return 0;
}

Queue

來排隊摟
鄭竣陽aka資訊社學術長 好像也講過

queue<int> a; // 預設用deque

queue<int, deque<int>> c;
queue<int, list<int>> d;

這個vector不能用

Structure

 

1     2     3     4

.front()

.back()

FIFO aka first in first out

out

in

範例

#include <iostream>
#include <queue>
using namespace std;
int main(int argc, char const *argv[]) {
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);
    cout << q.front() << ' ' << q.back() <<endl; // 1 3
    q.pop();
    cout << q.front() << ' ' << q.back() <<endl; // 2 3
    return 0;
}

Priority Queue

照號碼排隊喔

  • 加入一個元素
  • 查詢最大元素
  • 刪除最大元素

我只需要...

有個叫heap的資料結構

反正就是會排序的Queue

算是set的子集(不重要)

  • 查詢最大(小)O(1)
  • 插入O(log N)
  • 刪除O(log N)

用法

#include <iostream>
#include <priority_queue>
using namespace std;
int main(int argc, char const *argv[]) {
    priority_queue<int> pq;
    pq.push(1);//加入元素
    cout << pq.top() << '\n';//找最大
    pq.pop();//刪除最大
}

更改比較函式

#include <iostream>
#include <priority_queue>
using namespace std;
int main(int argc, char const *argv[]) {
    //要多寫一個底層容器
    priority_queue<int,vector<int>,greater<int> > pq;
    //最小在上面
    priority_queue<int,vector<int>,less<int> > pq;
    //最大在上面
}

用處

  • 不須排序只需極值
  • set被卡時間
  • 有點像急診
  • Greedy用的到
  • 最小生成樹

Set

一棵樹

什麼是樹呢?

完全連通無環圖

Depth

Root

leaf

Edge

Binary Search Tree

二元搜尋樹

Set是平衡二元搜尋樹

旋轉 or 換根,以保持tree的平衡,以免深度爆炸,影響複雜度

Unbalanced

Balanced

Set 內部是紅黑樹

我也不會

插入、查詢、刪除是O(log N)

基本用法

#include <iostream>
#include <set>
using namespace std;

int main() {
	set <int> s; //宣告 或是set <int, less<int>> s
	s.insert(5);//insert elements
	s.insert(2);
	s.insert(3);

	s.erase(s.begin());//use iter (= s.erase(5))
	cout<< *s.begin();//3
	cout<< *s.rbegin();//2
    
	multiset<int> ms; //可重複元素
}


一般set不能有重複元素,multiset可

orz.begin()

orz.end()

orz.rbegin()

還有一個unorder_set

Hash實作

插入刪除是常數較大的O(1)

有哪些應用呢?

  • 維護一個排序好的集合
  • 處理離散資料
  • Greedy Algorithm
  • 酷酷的Longest increasing subsequence (LIS)

Map

喔這也是紅黑樹

插入、查詢、刪除都是O(log N)

N是map大小

What can map do?

將一個KEY對應到一個VALUE

語法

#include <iostream>
#include <map>
using namespace std;

int main() {
    map <string, int> mp; // map<KEY, VALUE>
    mp["Iamweek"] = 1;//新增
    mp["Iamstrong"] = 0;
    mp["Iamweek"] = 666;//更改
    cout << mp["Iamweek"]; // 666

    mp.erase("Iamweek");//刪除
}

也可以unorder_map

key不排序,O(1)

能幹嘛?

  • 處理字串
  • KEY的範圍很大但用的很少->節省空間

有點像python的字典

Algorithm

簡單說就是STL的函式模板

min_element / max_element

最大最小

#include <iostream>
#include <set>
using namespace std;

int main() {
    //vector and deque
    *min_element(v.begin(),v.end());
    *max_element(v.begin(),v.end());
}


reverse

倒過來

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

int main()
{
    vector <int> arr;
    for (int i = 0; i < 5; ++i) arr.push_back(i);
    reverse(arr.begin(),arr.end());
    for (auto i : arr) cout<<i<<' ';//4 3 2 1 0
    return 0;
}

upper_bound()/lower_bound()

#include <iostream>
#include <set>
using namespace std;

int main() {
    //set
    s.upper_bound(x);//O(log N)
    upper_bound(s.begin(),s.end(),x);//O(n)
    
    //vector or deque
    //記得先sort
    upper_bound(v.begin(),v.end(),x);//O(log n)
}


就二分搜的概念,大於或大於等於

sort

O(N log N)~~

#include <iostream>
#include <set>
using namespace std;

int main() {
	vector <int> arr;
    for(int i = 5; i >= 0; --i) arr.push_back(i);
    sort(arr.begin(),arr.end(),greater<int>);//543210
    sort(arr.begin(),arr.end(),less<int>);//012345
}

Set的酷酷LIS

#include <iostream>
#include <set>
using namespace std;

int main() {
    int n; cin>>n;
    multiset <int> lis;
    for (int i = 0; i < n; ++i) {
        int a; cin>>a;
        lis.insert(a);
        auto iter = lis.upper_bound(a);
        if (iter != lis.end()) lis.erase(iter);
    }
    cout<< lis.size() << endl;
    return 0;
}

4叫我不要講,但我偏要

Thanks~

STL Presentation

By Lai Hong An

STL Presentation

  • 230