C++ set 是一個關聯式容器, set 容器裡面的元素是唯一的,具有不重複的特性,而且是有排序的容器, set 容器裡面元素的值是不可修改,但 set 容器可以插入或刪除元素, set 的實作方式通常是用紅黑樹 (red-black tree) 實作的。

# set 初始化

C++ set 初始化用法如下,
需要引入 include<set> 標頭檔

set<int> st{1, 2, 3, 4, 5};

從 c-style 陣列來初始化

int arr[] = {1, 2, 3, 4, 5};
set<int> st(arr, arr + 5);

# set 插入元素

set 使用 insert() 來插入元素。
用法如下,

set<int> st;
st.insert(1);
st.insert(2);
st.insert(3);
st.insert(4);
st.insert(5);

# set 讀取元素

由於 set 容器中沒有 at() 成員函數,也沒有 operator[] ,set 無法單純地隨機讀取某元素,但能透過 iterator 來讀取元素。

# 迴圈遍歷 set 容器

迴圈遍歷 set 容器的方式有幾種,
以下先介紹使用 range-based for loop 來遍歷 set 容器並且印出來,這邊故意將元素不按順序初始化以及插入,然後我們再來觀察看看是不是 set 會將其排序,同時看看是不是具有不重複性,

set<int> st = {3, 1};
st.insert(2);
st.insert(5);
st.insert(4);
st.insert(5);
st.insert(4);
for (auto& s: st) cout << s << " ";

輸出內容如下,從這個輸出結果發現是元素是由小到大排列,所以 set 容器裡面真的是會幫你排序的,在插入元素的同時會根據元素來進行排序,並且沒有元素重複。

1 2 3 4 5

迴圈也可以使用迭代器的方式,用法如下,

for (set<int>::iterator it = st.begin(); it != st.end(); it++) {
    cout << *it << " ";
}
// or
for (auto it = st.begin(); it != st.end(); it++) {
    cout << *it << " ";
}

如果要從後面印到前面的話,可以使用反向迭代器,如果嫌 iterator 迭代器名稱太長的話可以善用 auto 關鍵字讓編譯器去推導該變數類型,用法如下

for (auto it = st.rbegin(); it != st.rend(); it++) {
    cout << *it << " ";
}

使用反向迭代器的輸出結果如下

5 4 3 2 1

# set 刪除指定元素

set 刪除指定元素要使用 erase()

set<int> st{2, 4, 6, 8};
st.erase(2);
for (auto& s: st) cout << s << " ";

結果如下,

4 6 8

那 set 刪除不存在的元素呢?

set<int> st{2, 4, 6, 8};
auto ret = st.erase(2);
cout << ret << endl;
for (auto& s : st) cout << s << ' ';
ret = st.erase(3);
cout << endl << ret << endl;
for (auto& s : st) cout << s << ' ';

結果是可以這麼作的,不會發生什麼事。另外 erase() 會回傳告訴你刪除了幾個元素

1
4 6 8
0
4 6 8

# 清空 set 元素

要清空 set 容器的的話,要使用 clear()

set<int> st{1, 2, 3};
st.clear();

# set 判斷元素是否存在

set 要判斷指定元素是否存在的話有兩種方法,

# count()

第一種方法是使用 count() 成員函式, count() 存在該元素的話回傳 1 ,不存在的話回傳 0

set<int> st{2, 4, 6};
cout << st.count(4) << ", ";
cout << st.count(8);

結果如下,

1, 0

# find()

第二種方法是使用 find() 成員函式來判斷指定元素是否存在,
count() 不同的是 find() 有找到該指定元素的話會回傳指向該特定元素的 iterator,否則回傳 past-the-end (end ()) iterator

set<int> st = {2, 4, 6};
auto search = st.find(2);
if (search != st.end()) cout << "Found " << *search << endl;
else cout << "Not found\n";

Found 2

# 判斷 set 容器是否為空

要判斷 set 是否為空或是裡面有沒有元素的話,可以用 empty()

set<int> st;
st.clear();
if (st.empty()) cout << "Empty\n";
else cout << "Not empty";

Empty

# set vs. vector

  • 唯一性
    • set 跟 vector 不同之處是 set 容器裡面的元素是唯一的,具有不重複的特性,vector 則沒有這個限制。
  • 不可修改性
    • vector 可以修改元素的值,但 set 容器裡面元素的值是不可修改的
  • 順序性
    • set 是有序的,也就是裡面的元素會按照特定順序擺放,跟插入順序無關,vector 則不是。

# 參考資料

  • https://shengyu7697.github.io/std-set/