SET集合

事前準備

#include<set>
using namespace std;
int main(){

}

REd-black tree紅黑樹

 

set其實就是一棵紅黑樹

 

甚麼是紅黑樹?

 

REd-black tree紅黑樹

 

A red-black tree is a binary search tree with the following properties:

 

  1. Every node is colored with either red or black.

  2. All leaf (nil) nodes are colored with black; if a node’s child is missing then we will assume that it has a nil child in that place and this nil child is always colored black.

  3. Both children of a red node must be black nodes.

  4. Every path from a node n to a descendent leaf has the same number of black nodes (not counting node n). We call this number the black height of n, which is denoted by bh(n).

好複雜喔看不懂怎麼辦?

 

沒關係我也看不懂

 

其實set就是一棵二元搜索樹(BST)

 

還是不懂嗎?沒關係會用就好

 

 

 

set基本操作

set基本操作

set<int> s;

宣告一個 set

 

set裡面的每個元素都是唯一的(不會有重複)

 

set裡面的元素會自動排序(預設由小到大)

 

插入操作

s.insert(10)

時間複雜度O(log N)  N是集合大小

 

插入一個數到集合中

 

如果集合裡已經有10那什麼事都不會發生

刪除操作

s.erase(10)

時間複雜度O(log N)  N是集合大小

 

刪除一個集合中數(也可以用迭代器刪除)

 

如果集合裡沒有10, 那...你可能會Runtime Error

 

那怎麼避免呢?可以先加個判斷

查詢操作

if(s.find(10) != s.end())

s.end()會回傳s指向最後的迭代器

 

指向最後的迭代器並不是指向最後一個集合中元素

 

s.find(x)會回傳指向x的迭代器

 

如果x不再集合中會回傳會與s.end()相同

 

set其他操作

s.begin() 
//回傳第一個元素的迭代器
s.rbegin()
//回傳第一個反指標
//指向元素跟prev(s.end())相同
s.size() 
//回傳集合大小
set<int,greater<int>> s;
//宣告一個由大到小的集合

iterator迭代器小教室

iterator迭代器小教室

到底什麼是迭代器?

 

簡單來說就是幫助你遍歷STL容器的指標

 

不懂什麼是指標嗎?

 

指標會告訴你你要的變數存在哪裡

 

當然你就可以透過指標存取到你想要的變數

iterator迭代器小教室

迭代器其實是一種資料型態喔

 

要怎麼宣告呢?

vector<int> ::  iterator vit;
//宣告一個 vector<int>的迭代器
set<int> :: iterator sit;
//宣告一個 set<int>的迭代器

iterator迭代器小教室

哭阿怎麼這麼麻煩?有沒有簡單一點的方法

 

有喔!利用C++11以上提供的auto

auto it; 
// 錯誤用法 auto只是幫你自動判斷
// 並不是真的有這個資料型態
auto sit = s.begin();
// 正確用法 
// sit 會被判斷為 set<int> :: iterator
// 反正記得使用auto一定要完整初始化

iterator迭代器小教室

那要怎麼取到迭代器指向的值呢?

加個星號*就好了喔

要怎麼求集合S裡的第二個數呢?

可以使用 it++  ||  it = next(it)

 

auto it = s.begin();
cout << *it << '\n';
//輸出集合s第一個(最小)元素的值
it++; // 等價於 it = next(it);
cout << *it << '\n';
//輸出集合s第二個元素的值
auto itend = prev(s.end());
//雖然s.end()指向的不是集合中元素
//但它的前一個就是集合中的最後一個

iterator迭代器小教室

順便教一下range base for迴圈的用法

就是跟python很像的那種for迴圈

可以幫你輕鬆遍歷所有STL容器

 

 

set<int> s;

for(int x = 0; x < 10; x++)
	s.insert(x);
    
for(int i : s)
	cout << i << ' ';
//輸出會是0到9
//迴圈裡的i就會是集合裡的元素喔

iterator迭代器小教室

其實set有內建的upper_bound和lower_bound

時間複雜度都是O(log N),因為是在BST上做二分搜

但他們的回傳值都是iterator

所以強烈建議大家學好iterator,才能靈活運用



set<int> s
for(int x = 0; x < 10; x++)
	s.insert(i);
    
auto it = s.lower_bound(5);
cout << *it << '\n'; //輸出5

auto it = s.upper_bound(5);
cout << *it << '\n'; //輸出6

set實戰演練

set實戰演練

我們現在知道set可以快速的插入 ,刪除 ,取最大最小值

 

那請問...pq還有什麼用

 

pq能做到的set都可以(但set會稍微慢一點)

 

但是set不是不允許重複元素嗎?

 

用multiset就可以完美解決了(用法跟set幾乎完全相同)

 

 

multiset<int> s;

set實戰演練

還記的pq可以做什麼嗎?通通用set重作一遍!!

 

我們先來一題簡單的

 

TIOJ 1911 雲端列印

 

題目就是要你完成插入和取最大最小並刪除這幾個操作

 

根本就是set模板題阿

 

其實用set有點投機取巧但能做就好

set實戰演練

這邊提醒一下大家記得使用multiset因為回有重複數字

 

然後multiset使用有個特殊的地方

 

如果你想刪除multiset裡的值為x的元素的話

 

使用s.erase(x)會把所有值為x都刪除

 

如果要只刪除一個的話要這樣打

 

s.erase(s.find(x));

set進階挑戰

還記的之前教的用pq維護中位數嗎?當然set也可以

 

但這可沒有那麼簡單, pq可不能做喔

 

他要你支援刪除跟插入兩樣操作

 

CSES Sliding Median

 

詳細作法就讓同學回家想想吧

 

thanks for listening

 

MINGDAO CPP SET講義

By Gilbert Yeh

MINGDAO CPP SET講義

這個人懶死了,甚麼都沒有寫。

  • 370