SGISTL原始碼閱讀十九 set關聯式容器
阿新 • • 發佈:2018-11-14
SGISTL原始碼閱讀十九 set關聯式容器
前言
之前我們已經分析了vector
,list
,deque
三個容器。如果按照“資料在容器中的排列”特性,容器可以分為序列式(sequence)和關聯式(associative)兩種,前面學習過的三種容器都是序列式容器。
接下來我們將學習關聯式容器。標準的STL關聯式容器分為set
(集合)和map
(對映表)兩大類,以及這兩大類的衍生體muiltiset
(多鍵集合)和multimap
(多鍵對映表),他們的底層機制均以RB-Tree
紅黑樹完成,紅黑樹是一種特殊的二叉查詢樹。在STL中RB-Tree
也是一個獨立的容器,但是不開放對使用者使用。
關於紅黑樹我們在這裡不作過多介紹,但是紅黑樹的重要性是不言而喻的,這裡只給出紅黑樹的特性。
- 每個節點都是黑色或者紅色
- 根節點必須是黑色
- 每個葉子節點(NIL)是黑色
- 如果一個節點是紅色的,那麼它的子節點必須是黑色的
- 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑色節點
本次我們要分析的是set
集合,set
的特性是所有元素都會根據元素的鍵值自動被排列,(因為它的底層是紅黑樹)。set
的特殊之處是它元素的鍵值就是它的實值,實值就是鍵值。其實就是我們數學中學習到集合是一個意思,set
中的元素是保證唯一性但是不保證順序性的。
深入原始碼
set
的定義部分
#ifndef __STL_LIMITED_DEFAULT_TEMPLATES template <class Key, class Compare = less<Key>, class Alloc = alloc> #else template <class Key, class Compare, class Alloc = alloc> #endif class set { public: // typedefs: typedef Key key_type; typedef Key value_type; typedef Compare key_compare; typedef Compare value_compare; private: typedef rb_tree<key_type, value_type, identity<value_type>, key_compare, Alloc> rep_type; //底層結構為紅黑樹 rep_type t; public: //聲明瞭相應型別 typedef typename rep_type::const_pointer pointer; typedef typename rep_type::const_pointer const_pointer; typedef typename rep_type::const_reference reference; typedef typename rep_type::const_reference const_reference; typedef typename rep_type::const_iterator iterator; typedef typename rep_type::const_iterator const_iterator; typedef typename rep_type::const_reverse_iterator reverse_iterator; typedef typename rep_type::const_reverse_iterator const_reverse_iterator; typedef typename rep_type::size_type size_type; typedef typename rep_type::difference_type difference_type;
通過原始碼我們可以看到它的底層確實是紅黑樹,並且預設使用了STL的空間配置器。
set
的建構函式
因為使用了紅黑樹作為底層容器,相關的操作可以直接呼叫底層容器提供的方法。
#ifdef __STL_MEMBER_TEMPLATES //迭代器指定範圍構造 template <class InputIterator> set(InputIterator first, InputIterator last) : t(Compare()) { t.insert_unique(first, last); } template <class InputIterator> set(InputIterator first, InputIterator last, const Compare& comp) : t(comp) { t.insert_unique(first, last); } #else //普通指標指定範圍構造 set(const value_type* first, const value_type* last) : t(Compare()) { t.insert_unique(first, last); } set(const value_type* first, const value_type* last, const Compare& comp) : t(comp) { t.insert_unique(first, last); } set(const_iterator first, const_iterator last) : t(Compare()) { t.insert_unique(first, last); } set(const_iterator first, const_iterator last, const Compare& comp) : t(comp) { t.insert_unique(first, last); } #endif /* __STL_MEMBER_TEMPLATES */
操作符過載
//過載=,直接將底層的紅黑樹賦值即可
set(const set<Key, Compare, Alloc>& x) : t(x.t) {}
set<Key, Compare, Alloc>& operator=(const set<Key, Compare, Alloc>& x) {
t = x.t;
return *this;
}
//過載==
template <class Key, class Compare, class Alloc>
inline bool operator==(const set<Key, Compare, Alloc>& x,
const set<Key, Compare, Alloc>& y) {
return x.t == y.t;
}
//過載<
template <class Key, class Compare, class Alloc>
inline bool operator<(const set<Key, Compare, Alloc>& x,
const set<Key, Compare, Alloc>& y) {
return x.t < y.t;
}
set
的相關操作
基本操作
//比較鍵值
key_compare key_comp() const { return t.key_comp(); }
//比較實值
value_compare value_comp() const { return t.key_comp(); }
//返回set的起始迭代器
iterator begin() const { return t.begin(); }
//返回set的末尾迭代器
iterator end() const { return t.end(); }
reverse_iterator rbegin() const { return t.rbegin(); }
reverse_iterator rend() const { return t.rend(); }
//判斷set是否為空
bool empty() const { return t.empty(); }
//返回set的大小
size_type size() const { return t.size(); }
size_type max_size() const { return t.max_size(); }
//互換兩個set
void swap(set<Key, Compare, Alloc>& x) { t.swap(x.t); }
//...
iterator find(const key_type& x) const { return t.find(x); }
size_type count(const key_type& x) const { return t.count(x); }
//返回指向小於(或等於)某值的第一個元素的迭代器
iterator lower_bound(const key_type& x) const {
return t.lower_bound(x);
}
iterator upper_bound(const key_type& x) const {
return t.upper_bound(x);
}
pair<iterator,iterator> equal_range(const key_type& x) const {
return t.equal_range(x);
}
insert
插入操作
set
所有需要使用的方法紅黑樹都已經實現了,所以直接呼叫即可
//插入一個值為x的元素
typedef pair<iterator, bool> pair_iterator_bool;
pair<iterator,bool> insert(const value_type& x) {
//insert_unique,不允許重複的值
pair<typename rep_type::iterator, bool> p = t.insert_unique(x);
//返回pair(之後會講到),第一個代表指向插入節點的迭代器,第二個代表插入是否成功
return pair<iterator, bool>(p.first, p.second);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_unique((rep_iterator&)position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_unique(first, last);
}
#else
void insert(const_iterator first, const_iterator last) {
t.insert_unique(first, last);
}
void insert(const value_type* first, const value_type* last) {
t.insert_unique(first, last);
}
erase
/clear
刪除操作
void erase(iterator position) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)position);
}
size_type erase(const key_type& x) {
return t.erase(x);
}
void erase(iterator first, iterator last) {
typedef typename rep_type::iterator rep_iterator;
t.erase((rep_iterator&)first, (rep_iterator&)last);
}
void clear() { t.clear(); }
關於set
的操作總結
1. begin()--返回指向第一個元素的迭代器
2. clear()--清除所有元素
3. count()--返回某個值元素的個數
4. empty()--如果集合為空,返回true
5. end()--返回指向最後一個元素的迭代器
6. equal_range()--返回集合中與給定值相等的上下限的兩個迭代器
7. erase()--刪除集合中的元素
8. find()--返回一個指向被查詢到元素的迭代器
9. get_allocator()--返回集合的分配器
10. insert()--在集合中插入元素
11. lower_bound()--返回指向大於(或等於)某值的第一個元素的迭代器
12. key_comp()--返回一個用於元素間值比較的函式
13. max_size()--返回集合能容納的元素的最大限值
14. rbegin()--返回指向集合中最後一個元素的反向迭代器
15. rend()--返回指向集合中第一個元素的反向迭代器
16. size()--集合中元素的數目
17. swap()--交換兩個集合變數
18. upper_bound()--返回大於某個值元素的迭代器
19. value_comp()--返回一個用於比較元素間的值的函式
set
的簡單使用
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> myset{0};
myset.insert(5);
myset.insert(2);
myset.insert(6);
//獲取指向頭尾的迭代器
set<int>::iterator first = myset.begin();
set<int>::iterator last = myset.end();
while(first != last)
{
cout << *first << endl;
first++;
}
myset.erase(myset.begin(), myset.end());
cout << "size:" << myset.size() << endl;
//嘗試插入已存在的元素
//查詢2的位置
set<int>::iterator ite1 = myset.find(2);
if(ite1 != myset.end())
{
cout << "i find it" << endl;
}
else
{
cout << "not found" << endl;
}
return 0;
}
關於multiset
multiset
和set
的特性和用法一致,唯一的差別就是multiset
允許鍵值重複。
這是因為呼叫紅黑樹的插入操作函式不同造成而造成的區別。set
呼叫的是insert_unique
函式而multiset
呼叫的是insert_equal
函式
深入原始碼
沒有貼出全部原始碼,因為大部分和set
相同
iterator insert(const value_type& x) {
//呼叫的是insert_equal函式
return t.insert_equal(x);
}
iterator insert(iterator position, const value_type& x) {
typedef typename rep_type::iterator rep_iterator;
return t.insert_equal((rep_iterator&)position, x);
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(InputIterator first, InputIterator last) {
t.insert_equal(first, last);
}
#else
void insert(const value_type* first, const value_type* last) {
t.insert_equal(first, last);
}
void insert(const_iterator first, const_iterator last) {
t.insert_equal(first, last);
}