1、Set
set 的特性是,所有元素都會根據元素的鍵值自動被排序。set 的元素不像 map 那樣可以同時擁有實值(value)和鍵值(key),set 元素的鍵值就是實值,實值就是鍵值。 set 不允許兩個元素有相同的鍵值。
因爲 set 元素值就是其鍵值,關係到 set 元素的排列規則,如果任意改變 set 元素值,會嚴重破壞 set 組織。所以 set 的迭代器是 const_iterator,杜絕寫入操作。
set 擁有與 list 相同的某些性質:當客戶端對它進行元素新增操作或刪除操作時,操作之前的所有迭代器,在操作之後都依然有效。當然,被刪除的那個元素的迭代器必然是個例外。
由於 RB-tree 是一種平衡二叉搜索樹,自動排序的效果很不錯,所以標準 STL set 即以 RB-tree 爲底層機制。又由於 set 所開放的各種操作接口, RB-tree 也都提供了,所以幾乎所有的 set 操作行爲,都只是轉調用 RB-tree 的操作行爲而已。大概的代碼如下:
template<class Key, class Compare = less<Key>, class Alloc = alloc>
class set
{
public:
typedef Key key_type;
typedef Key value_type;
typedef Compare key_compare; // key 的比較函數
typedef Compare value_compare; // value 的比較函數
typedef rb_tree<......> rep_type;
typedef typename rep_type::const_pointer pointer; //一堆跟萃取有關的類型,都是 const 的
......
rep_type t; // 底層採用紅黑樹來表現 set
public:
set(); //一系列重載函數
iterator begin() const { return t.begin(); }
iterator end() const { return t.end(); }
bool empty() const { return t.empty(): }
size_type size() const { return t.size(); }
xxx insert( ... ) { return t.xxxx(); }
xxx erase(...) { return t.xxxx(); }
};
2、Map
map 特性是,所有元素都會根據元素的鍵值自動被排序。map 的所有元素都是pair,同時擁有實值(value)和鍵值(key)。pair的第一個元素被視爲鍵值,第二元素被視爲實值。map不允許兩個元素擁有相同的鍵值。
template<class T1, class T2>
struct pair
{
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b){}
};
我們不能更改 map 的鍵值,因爲鍵值關係到 map 的排序規則。但是我們可以修改元素的實值,因爲實值並不影響 map 元素的排列規則。
和 set 一樣 map 底層也使用的是 RB-tree 來實現的。只是比較元素大小時,map 比較的是 pair 的第一個元素。大概代碼如下:
template<......>
class map
{
public:
typedef Key key_type; //鍵值類型
typedef T data_type; //實值類型
typedef T mapped_type;
typedef pair<const Key, T> value_type; //元素型別
typedef Compare key_compare; //鍵值比較函數
Compare comp;
public:
//比較時,使用pair 的第一個元素
bool operator()( const value_type& x, const value_type& y ) const
{
return comp( x.first, y.first);
}
private:
typedef rb_tree<key_type, value_type, select1st<value_type>, key_compare, Alloc> rep_type;
rep_type t; //以紅黑樹作爲 底層,表現map
//剩下的函數跟 set 基本是一樣的
};
3、multiset 和 multimap
multiset 特性以及用法和 set 完全相同,唯一的差別在於它允許鍵值重複,因此它的插入操作採用的是底層機制 RB-tree 的 insert_equal() 而非 insert_unique()。
而multimap 和 map 完全相同,唯一的差別也是允許鍵值的重複,也是使用了 RB-tree 的 insert_equal() 而非 insert_unique() 函數。
感謝大家,我是假裝很努力的YoungYangD(小羊)。
參考資料:
《STL源碼剖析》