Red-Black tree(紅黑樹)是平衡二叉搜索樹(balanced binary search tree)中常被使用的一種。平衡二叉搜索樹的特色:排列規則有禮 search 和 insert,並保持高度平衡—————無任何節點過深。node
rb_tree提供「便利」操做及iterators。按正常規則(++ite)遍歷,便能得到排序狀態(sorted)。編程
由於rb_tree有必定的排序規則,因此咱們不該該使用rb_tree的iterator改變元素值 編程層面並未禁止此事。 這樣設計的緣由是:rb_tree是set和map的底層實現依託,而map運行元素的 data 被改變,只有元素的 key 纔是不可改變的。數組
rb_tree提供兩種insertion操做:insert_unuque()和insert_equal()。前者表示節點的key必定能夠在整個tree中獨一無二,不然插入失敗;後者表示節點的key能夠重複。app
template <class Key, class Value, class KeyOfValue, class Compare, class Alloc = alloc> class te_tree{ protected: typedef __rb_tree_node<Value> rb_tree_node; ... public: typedef rb_tree_node* link_type; ... protected: size_type node_count; //記錄rb_tree的節點數量 link_type header; //頭指針 Compare key_compare; //key的大小比較規則;應該是個function object ... }
模板中Key+value一塊兒合成爲value,KeyOfValue就是告訴模板如何肯定value中的key是什麼。less
set/multiset是以rb_tree爲底層結構,所以有 元素自動排序 的特性。排序是依據 key 進行的,而set/multiset元素的 value和key合一:value就是key。 同時,set/multiset提供遍歷操做和迭代器。按照正常的++ite遍歷,便能得到排序狀態後的序列。ide
咱們沒法使用set/multiset的迭代器改變元素的值,會打亂rb_tree中的順序。因此set/multiset使用的迭代器就是rb_tree的 const iterator ,目的就是禁止用戶對元素進行賦值。函數
set元素的key必須獨一無二,所以insert()用的是rb_tree的 insert_unique() ;multiset元素的key能夠重複,所以insert()用的是rb_tree的 insert_equal() 。設計
template <class Key, class Compare = less<Key>, class Alloc = alloc> class set { 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>,//VC6中沒有identity,提供了一個與identity類似的操做 key_compare, Alloc> rep_type; rep_type t; public: typedef typename rep_type::const_iterator iterator; ... };
set的全部操做,都轉交給底層的t進行操做,因此能夠將set看做一個容器適配器(container adapter)。指針
map/multimap以rb_tree爲底層結構,所以有 元素自動排序 的特性。同時,set/multiset提供遍歷操做和迭代器。按照正常的++ite遍歷,便能得到排序狀態後的序列。code
咱們沒法使用map/multimap的迭代器改變元素的key(由於key有其謹慎的排序規則),可是能夠用它來改變元素的data。因map/multimap內部將用戶指定的 key type 設置爲const, 以便能禁止用戶對元素的key賦值。
map元素的key必須獨一無二,所以insert()用的是rb_tree的 insert_unique() ;multimap元素的key能夠重複,所以insert()用的是rb_tree的 insert_equal() 。
template <class Key, class T, class Compare = less<Key>, class Alloc=alloc> 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; private typedef rb_tree<key_type, value_type, select1st<value_type>, //vc6中一樣沒有此函數,但提供了類似的功能 key_compare, Alloc> rep_type; rep_type t; public: typedef typename rep_type::iterator iterator; ... };
map的[]操做符號用來返回指定key所對應的data, 若是key不存在,則會建立一個帶有此key的元素放入map。
hashtable做爲unordered_set和unordered_map的底層結構。hashtable主要的思想就是將給定的元素經過哈希函數計算後獲得一個哈希碼(Hash Code),這個給定的元素就能夠看做爲value, 而生成的哈希碼能夠看爲key。有如下的結論:
以int爲元素類型,一個hashtable就是用來表現hashcode和元素之間的映射關係,能夠定義一個必定大小的數組用來保存這種映射關係。hashtable中的每個位置稱爲一個bucket。假設hashtable的大小爲53,如今有些須要存放的數據{59, 63, 108, 2, 53, 55}。咱們能夠用一個簡單的哈希函數來計算哈希碼:取餘法
static int indexFor(int h, int length) { return h % length; }
這樣59就存放在序號爲6的位置;63就存放在序號爲10的位置;108就在序號爲2的位置上;2就在序號爲2的位置上;53就存放在序號爲0的位置;55就存放在序號爲2的位置。
經過這樣的方式能夠快速訪問到相應的元素,但也會發現108,2,55三個數的哈希碼衝突了,產生哈希碼的過程當中不免會產生衝突,一種好的衝突解決方案決定了hashtable的效率。目前經常使用的一種衝突解決方案是Separate Chaining。
這樣hashtable中每個bucket都存放一個鏈表,全部衝突的哈希碼都放在這個鏈表中。雖然說鏈表的查找是一個線型過程,可是當鏈表不長時查找的效率仍是不差的,當鏈表過長時,能夠將鏈表轉換爲紅黑樹提升查找效率。當整個hashtable中存放的數據過多,會由於鏈表過長致使查找效率急速降低。可是目前這個界限沒有明確的界定,根據你們的經驗來講,當hashtable中的數據個數大於bucket的個數時,效率就會受到影響。這個時候就須要對hashtable的bucket進行擴充,這個擴充過程通常來講是將bucket的數量乘以2,而後選出這個2倍數附近的一個 素數 。對於這樣固定模式的擴充,能夠不用在使用時進行計算,而是在程序中將須要擴充的數字寫好,在使用時直接調用。
static const unsigned long __stl_prime_list[__stl_num_primes] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 3221225473ul, 4294967291ul };
在擴充以後,由於bucket的個數發生了變化因此須要對整個hashtable進行從新計算。
template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc=alloc> class hashtable { public: typedef HashFcn hasher; typedef EqualKey key_equal; typedef size_t size_type; private: hasher hash; key_equal equals; ExtractKey get_key; typedef __hashtable_node<Value> node;//單向鏈表 vector<node*, Alloc> buckets; size_type num_elements; public: size_type bucket_count() const { return buckets.size();} ... }