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

操作的時間複雜度都是

剛剛介紹到的都是 線性資料結構

O(1)
O(n)

Summary

這些容器的 methods 都很相似

不過最常用到的還是

vector 跟 pair

Next

接下來要介紹的是 非線性資料結構

O( \log n )

操作的時間複雜度會出現

Next

 非線性資料結構 也是競賽中 最常用到 的資料結構

set , map , priority_queue
multiset , unordered_map

set

集合

「 不會有重複的元素 」

可以快速的  搜尋 , 插入 , 移除 元素

不會有重複的元素 」

O( \log n )

🙉🙉🙉

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

可以看到

在連續插入單調的元素時:

搜尋的時間複雜度

會從

退化成

O( \log n )
O( n )

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
O( \log n )

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) 的時間複雜度是:
O( cnt(val) + \log n )

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 一樣,也是 動態平衡的樹狀結構

 搜尋 , 插入 , 移除 元素

O( \log n )

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
O( \log n )

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

O(1)

Heap Intro

99

10

9

55

6

20

5

remove Max element

Heap Intro

10

9

55

6

20

5

remove Max element

O(\log n )

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

O(\log n )

priority_queue

Header :

#include<queue>

Construct :

priority_queue<int> pq;
// priority_queue<T> name;

Methods :

.size()
.empty()
.push(val)
.pop()
.top()
O( \log n )
O( 1 )

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

O( n \log k )
O( n \log n )

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

O( \log n )
O( 1 )

但是不一定會比 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 :

O(SIZE)

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