set集合容器實現了紅黑樹(Red-Black Tree)的平衡二叉件所屬的數據結構,在插入元素時,他會自動調整二叉樹的排列,把該元素放到適當的位置,以確保每個子樹根節點的鍵值大於左子樹所有節點的鍵值,而小於右子樹所有節點的鍵值;另外,還得確保根節點左子樹的高度與右子樹的高度相等,這樣,二叉樹的高度最小,從而檢索速度最快。要注意的是,它不會重複插入相同鍵值的元素,而採取忽略處理。
平衡二叉檢索樹的檢索使用中序遍歷算法,檢索效率高於vector、deque、和list等容器。另外,採用中序遍歷算法可將鍵值由小到大遍歷出來,所以,可以理解爲平衡二叉檢索樹在插入元素時,就會自動將元素按鍵值由小到大的順序排列。
對於set容器中的鍵值,不可直接去修改。因爲如果把容器中的一個鍵值修改了,set容器就會根據新的鍵值旋轉子樹,以保持新的平衡,這樣,修改的鍵值很可能就不在原先那個位置上了。換句話來說,構造set集合的主要目的就是爲了快速檢索。
multiset(多重集合容器)、map(映照容器)和multimap(多重映照容器)的內部結構也是平衡二叉檢索樹。
使用set對象前,需要程序的頭文件中包含聲明“#include <set>”
1.1元素的插入與中序遍歷
#include <set>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//定義一個元素類型爲int的集合對象s,當前沒有任何元素
set<int> s;
//插入5個元素,但由於8被插入了兩次,第二次插入的8並沒有執行
s.insert(8); //第一次插入8,可以插入
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8,重複元素,不可以插入
//中序遍歷集合中的元素
set<int>::iterator it; //定義前向迭代器
for (it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}
cout << endl;
return 0;
}
1.2 元素的反向遍歷
#include <set>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//定義一個元素類型爲int的集合對象s,當前沒有任何元素
set<int> s;
//插入5個元素,但由於8被插入了兩次,第二次插入的8並沒有執行
s.insert(8); //第一次插入8,可以插入
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8,重複元素,不可以插入
//反向遍歷集合中的元素
set<int>::reverse_iterator rit; //定義反向迭代器
for (rit = s.rbegin(); rit != s.rend(); rit++) {
cout << *rit << " ";
}
return 0;
}
1.3元素的刪除
刪除的對象可以是某個迭代器位置上的元素、等於某鍵值的元素、一個區間上的元素和清空集合。
#include <set>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//定義一個元素類型爲int的集合對象s,當前沒有任何元素
set<int> s;
//插入5個元素,但由於8被插入了兩次,第二次插入的8並沒有執行
s.insert(8); //第一次插入8,可以插入
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8,重複元素,不可以插入
//刪除鍵值爲6的那個元素
s.erase(6);
//中序遍歷集合中的元素
//定義前向迭代器
set<int>::iterator it;
for (it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}
return 0;
}
1.4元素的檢索
#include <set>
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
//定義一個元素類型爲int的集合對象s,當前沒有任何元素
set<int> s;
//插入5個元素,但由於8被插入了兩次,第二次插入的8並沒有執行
s.insert(8); //第一次插入8,可以插入
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8,重複元素,不可以插入
//定義前向迭代器
set<int>::iterator it;
//查找鍵值爲6的元素
it = s.find(6);
if (it != s.end()) {
cout << *it << endl;
} else {//沒找到
cout << "not find it" << endl;
}
it = s.find(20);
if (it != s.end()) {
cout << *it << endl;
} else {
cout << "沒有找到" << endl;
}
return 0;
}
1.5自定義比較函數
(1)如果元素不是結構體,那麼,可以編寫比較函數。
#include <set>
#include <iostream>
using namespace std;
//自定義比較函數,Compare,重載"()"操作符
struct Compare
{
bool operator() (const int &a, const int &b)
{
if (a != b)
return a > b;
else
return a > b;
}
};
int main(int argc, const char * argv[]) {
//定義一個元素類型爲int的集合對象s,當前沒有任何元素
set<int, Compare> s;
//插入5個元素,但由於8被插入了兩次,第二次插入的8並沒有執行
s.insert(8); //第一次插入8,可以插入
s.insert(1);
s.insert(12);
s.insert(6);
s.insert(8); //第二次插入8,重複元素,不可以插入
//定義前向迭代器
set<int, Compare>::iterator it;
for (it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}
cout << endl;
//清空元素
s.clear();
cout << s.size() << endl;
return 0;
}
(2)如果元素是結構體,那麼,可以直接把比較函數放在結構體內。
#include <set>
#include <string>
#include <iostream>
using namespace std;
struct Info
{
string name;
float score;
//重載“<”操作符,自定義排序規則
bool operator < (const Info &a) const
{
//按score由大到小排列。如果要由小到大排列,使用“>”號即可。
return a.score < score;
}
};
int main(int argc, const char * argv[]) {
//定義元素類型爲Info結構體的集合對象s,當前沒有任何元素
set<Info> s;
Info info;
//插入三個元素
info.name = "Kevin";
info.score = 90;
s.insert(info);
info.name = "Yuki";
info.score = 80;
s.insert(info);
info.name = "Tony";
info.score = 85;
s.insert(info);
set<Info>::iterator it; //定義前向迭代器
for (it = s.begin(); it != s.end(); it++) {
cout << (*it).name << " : " << (*it).score << endl;
}
cout << endl;
return 0;
}