红黑树,作为一种广泛使用的数据结构,我想大家应该都不会陌生。

谈到红黑树的用途,最广为人知的应该就是红黑树在C++ STL中的应用了,在set, multiset, map, multimap等中,都应用了红黑树。但是,rb_tree本身并不开放给外界使用。

今天,我将介绍,STL源码中,红黑树的具体实现(因为篇幅所限,这里不包括删除操作)。

因为文章的主要目的是分析STL中的源码,所以对于红黑树的具体实现并不展开,这类文章,大家可以到网上查找。这里推荐wiki上的一篇。

首先,我还是简要的介绍一下红黑树的构造、维护思想。

红黑树:

红黑树是二叉查找树(BST),同时也是一种平衡二叉查找树。

虽然它的平衡不如AVL树,但是,它和AVL树一样都对插入时间、删除时间和查找时间提供了最好可能的最坏情况担保。

它可以在O(logn)时间内做查找,插入和删除,这里的n是树中元素的数目。

红黑树性质:
红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 
性质1. 节点是红色或黑色。 
性质2. 根是黑色。 
性质3. 所有叶子都是黑色(叶子是NIL节点)。 
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 
性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。 
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。
因为根据属性5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。 

红黑树操作:
恢复红黑树的属性需要少量(O(log n))的颜色变更(实际是非常快速的)和不超过三次树旋转(对于插入操作是两次)。
虽然插入和删除很复杂,但操作时间仍可以保持为 O(log n) 次。 
插入节点:
在讨论红黑树的插入操作之前必须要明白,任何一个即将插入的新结点的初始颜色都为红色。这一点很容易理解,因为插入黑点会增加某条路径上黑结点的数目,从而导致整棵树黑高度的不平衡。
如果新结点父结点为红色时(如图2所示),将会违返红黑树性质:一条路径上不能出现相邻的两个红色结点。这时就需要通过一系列操作来使红黑树保持平衡。

删除节点:

1、删除操作中真正被删除的必定是只有一个红色孩子或没有孩子的结点。

2、如果真正的删除点是一个红色结点,那么它必定是一个叶子结点。

STL源码实现:
 

一、下面代码定义了红黑树的节点信息:

[cpp] view plaincopy
  1. typedef bool __rb_tree_color_type;              // 节点颜色
  2. const __rb_tree_color_type __rb_tree_red = false;       // 红色为 0
  3. const __rb_tree_color_type __rb_tree_black = true;      // 黑色为 1
  4. struct __rb_tree_node_base
  5. {
  6. typedef __rb_tree_color_type color_type;
  7. typedef __rb_tree_node_base* base_ptr;
  8. color_type color;   // 節點顏色,非紅即黑。
  9. base_ptr parent;    // RB 樹的許多操作,必須知道父節點。
  10. base_ptr left;      // 指向左節點。
  11. base_ptr right;     // 指向右節點。
  12. static base_ptr minimum(base_ptr x)
  13. {
  14. while (x->left != 0) x = x->left; // 一直向左走,就會找到最小值,
  15. return x;                           // 這是二元搜尋樹的特性。
  16. }
  17. static base_ptr maximum(base_ptr x)
  18. {
  19. while (x->right != 0) x = x->right;   // 一直向右走,就會找到最大值,
  20. return x;                           // 這是二元搜尋樹的特性。
  21. }
  22. };
  23. template <class Value>
  24. struct __rb_tree_node : public __rb_tree_node_base
  25. {
  26. typedef __rb_tree_node<Value>* link_type;
  27. Value value_field;  // 節點實值
  28. };

由上面的定义可以看出来,每个结点维护了三个指针和两个信息:父结点parent,左子结点left,右子结点right,同时还有一个颜色标记color,再就是结点的值value_field。同时可以求得当以某个结点为根的最小与最大结点。

二、红黑树的迭代器定义:

迭代器是STL里面非常重要的一部分,这里就不细说了。我们直接来看看__rb_tree_iterator提供了哪些功能。因为,__rb_tree_iterator继承自__rb_tree_base_iterator

所以我们先来看__rb_tree_base_iterator这个结构。

[cpp] view plaincopy
  1. truct __rb_tree_base_iterator
  2. {
  3. typedef __rb_tree_node_base::base_ptr base_ptr;
  4. typedef bidirectional_iterator_tag iterator_category;
  5. typedef ptrdiff_t difference_type;
  6. base_ptr node;  // 它用来与容器之间产生一个连结关系(make a reference)
  7. // 以下其實可實作於 operator++ 內,因為再無他處會呼叫此函式了。
  8. void increment()
  9. {
  10. if (node->right != 0) {      // 如果有右子節點。狀況(1)
  11. node = node->right;      // 就向右走
  12. while (node->left != 0)  // 然後一直往左子樹走到底
  13. node = node->left;       // 即是解答
  14. }
  15. else {                  // 沒有右子節點。狀況(2)
  16. base_ptr y = node->parent;   // 找出父節點
  17. while (node == y->right) {   // 如果現行節點本身是個右子節點,
  18. node = y;               // 就一直上溯,直到「不為右子節點」止。
  19. y = y->parent;
  20. }
  21. if (node->right != y)        // 「若此時的右子節點不等於此時的父節點」。
  22. node = y;               // 狀況(3) 此時的父節點即為解答。
  23. // 否則此時的node 為解答。狀況(4)
  24. }
  25. // 注意,以上判斷「若此時的右子節點不等於此時的父節點」,是為了應付一種
  26. // 特殊情況:我們欲尋找根節點的下一節點,而恰巧根節點無右子節點。
  27. // 當然,以上特殊作法必須配合 RB-tree 根節點與特殊之header 之間的
  28. // 特殊關係。
  29. }
  30. // 以下其實可實作於 operator-- 內,因為再無他處會呼叫此函式了。
  31. void decrement()
  32. {
  33. if (node->color == __rb_tree_red &&  // 如果是紅節點,且
  34. node->parent->parent == node)     // 父節點的父節點等於自己,
  35. node = node->right;              // 狀況(1) 右子節點即為解答。
  36. // 以上情況發生於node為header時(亦即 node 為 end() 時)。
  37. // 注意,header 之右子節點即 mostright,指向整棵樹的 max 節點。
  38. else if (node->left != 0) {          // 如果有左子節點。狀況(2)
  39. base_ptr y = node->left;         // 令y指向左子節點
  40. while (y->right != 0)                // 當y有右子節點時
  41. y = y->right;                    // 一直往右子節點走到底
  42. node = y;                       // 最後即為答案
  43. }
  44. else {                          // 既非根節點,亦無左子節點。
  45. base_ptr y = node->parent;           // 狀況(3) 找出父節點
  46. while (node == y->left) {            // 當現行節點身為左子節點
  47. node = y;                       // 一直交替往上走,直到現行節點
  48. y = y->parent;                   // 不為左子節點
  49. }
  50. node = y;                       // 此時之父節點即為答案
  51. }
  52. }
  53. };

可以看到__rb_tree_base_iterator里面只有两个函数:increment()decrement()

这两个函数也是很好理解:

increment():找到比当前节点大的最小的那个节点。用于__rb_tree_iterator中重载++操作符的调用。

decrement():找到比当前节点小的最大的那个节点。用于__rb_tree_iterator中重载--操作符的调用。

再来看看__rb_tree_iterator提供了哪些功能:

[cpp] view plaincopy
  1. template <class Value, class Ref, class Ptr>
  2. struct __rb_tree_iterator : public __rb_tree_base_iterator
  3. {
  4. typedef Value value_type;
  5. typedef Ref reference;
  6. typedef Ptr pointer;
  7. typedef __rb_tree_iterator<Value, Value&, Value*>     iterator;
  8. typedef __rb_tree_iterator<Value, const Value&, const Value*> const_iterator;
  9. typedef __rb_tree_iterator<Value, Ref, Ptr>   self;
  10. typedef __rb_tree_node<Value>* link_type;
  11. __rb_tree_iterator() {}
  12. __rb_tree_iterator(link_type x) { node = x; }
  13. __rb_tree_iterator(const iterator& it) { node = it.node; }
  14. reference operator*() const { return link_type(node)->value_field; }
  15. #ifndef __SGI_STL_NO_ARROW_OPERATOR
  16. pointer operator->() const { return &(operator*()); }
  17. #endif /* __SGI_STL_NO_ARROW_OPERATOR */
  18. self& operator++() { increment(); return *this; }   //++操作符
  19. self operator++(int) {
  20. self tmp = *this;
  21. increment();
  22. return tmp;
  23. }
  24. self& operator--() { decrement(); return *this; }   //--操作符
  25. self operator--(int) {
  26. self tmp = *this;
  27. decrement();
  28. return tmp;
  29. }
  30. };
  31. inline bool operator==(const __rb_tree_base_iterator& x,
  32. const __rb_tree_base_iterator& y) {
  33. return x.node == y.node;
  34. // 兩個迭代器相等,意指其所指的節點相等。
  35. }
  36. inline bool operator!=(const __rb_tree_base_iterator& x,
  37. const __rb_tree_base_iterator& y) {
  38. return x.node != y.node;
  39. // 兩個迭代器不等,意指其所指的節點不等。
  40. }

上述代码等价于下面代码,结构功能一目了然:

[cpp] view plaincopy
  1. struct __rb_tree_iterator
  2. {
  3. typedef __rb_tree_node<T>* link_type;
  4. operator*();
  5. operator->();
  6. operator++();
  7. operator++(int);
  8. operator--();
  9. operator--(int);
  10. }

三、RB_tree的数据结构:

下面是rb_tree的定义,你可以看到里面有专属的空间配置器,因为红黑树是动态增长的,所以每次增加或删除结点时都要进行配置,它有一个专用的空间配置器,用来每次申请一个结点的内存或归还一个结点的内存。还有各种类别定义,用来维护整棵RB_tree的三笔数据(其中有个仿函数,functor,用来变现节点的大小比较方式),以及一些member functions的定义或声明。

1、专属的空间配置器rb_tree_node_allocator,每次配置一个节点,它使用的是simple_alloc<>。

[cpp] view plaincopy
  1. template <class Key, class Value, class KeyOfValue, class Compare,
  2. class Alloc = alloc>
  3. class rb_tree {
  4. protected:
  5. typedef void* void_pointer;
  6. typedef __rb_tree_node_base* base_ptr;
  7. typedef __rb_tree_node<Value> rb_tree_node;
  8. typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator;
  9. typedef __rb_tree_color_type color_type;
  10. ...
  11. };

2、一些与节点相关的函数:get_node(),put_node(),create_node(),clone_node(),destroy_node()。

[cpp] view plaincopy
  1. public:
  2. // 注意,沒有定義 iterator(喔,不,定義在後面)
  3. typedef Key key_type;
  4. typedef Value value_type;
  5. typedef value_type* pointer;
  6. typedef const value_type* const_pointer;
  7. typedef value_type& reference;
  8. typedef const value_type& const_reference;
  9. typedef rb_tree_node* link_type;
  10. typedef size_t size_type;
  11. typedef ptrdiff_t difference_type;
  12. protected:
  13. link_type <strong>get_node</strong>() { return rb_tree_node_allocator::allocate(); }
  14. void put_node(link_type p) { rb_tree_node_allocator::deallocate(p); }
  15. link_type <strong>create_node</strong>(const value_type& x) {
  16. link_type tmp = get_node();         // 配置空間
  17. __STL_TRY {
  18. construct(&tmp->value_field, x);   // 建構內容
  19. }
  20. __STL_UNWIND(put_node(tmp));
  21. return tmp;
  22. }
  23. link_type <strong>clone_node</strong>(link_type x) {  // 複製一個節點(的值和色)
  24. link_type tmp = create_node(x->value_field);
  25. tmp->color = x->color;
  26. tmp->left = 0;
  27. tmp->right = 0;
  28. return tmp;
  29. }
  30. void <strong>destroy_node</strong>(link_type p) {
  31. destroy(&p->value_field);        // 解構內容
  32. put_node(p);                    // 釋還記憶體
  33. }

3、rb_tree的构造函数

1、以现有的RB_tree复制一个新的RB_tree

2、创造一个空的RB_tree

[cpp] view plaincopy
  1. void init() {
  2. header = get_node();    // 產生一個節點空間,令 header 指向它
  3. color(header) = __rb_tree_red; // 令 header 為紅色,用來區分 header
  4. // 和 root(在 iterator.operator++ 中)
  5. root() = 0;
  6. leftmost() = header;    // 令 header 的左子節點為自己。
  7. rightmost() = header;   // 令 header 的右子節點為自己。
  8. }
  9. public:
  10. // allocation/deallocation
  11. rb_tree(const Compare& comp = Compare())
  12. : node_count(0), key_compare(comp) { init(); }
  13. // 以另一個 rb_tree 物件 x 為初值
  14. rb_tree(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x)
  15. : node_count(0), key_compare(x.key_compare)
  16. {
  17. header = get_node();    // 產生一個節點空間,令 header 指向它
  18. color(header) = __rb_tree_red;  // 令 header 為紅色
  19. if (x.root() == 0) {    //  如果 x 是個空白樹
  20. root() = 0;
  21. leftmost() = header;  // 令 header 的左子節點為自己。
  22. rightmost() = header; // 令 header 的右子節點為自己。
  23. }
  24. else {  //  x 不是一個空白樹
  25. __STL_TRY {
  26. root() = __copy(x.root(), header);      // ???
  27. }
  28. __STL_UNWIND(put_node(header));
  29. leftmost() = minimum(root()); // 令 header 的左子節點為最小節點
  30. rightmost() = maximum(root());    // 令 header 的右子節點為最大節點
  31. }
  32. node_count = x.node_count;
  33. }
  34. ~rb_tree() {
  35. clear();
  36. put_node(header);
  37. }
  38. rb_tree<Key, Value, KeyOfValue, Compare, Alloc>&
  39. operator=(const rb_tree<Key, Value, KeyOfValue, Compare, Alloc>& x);

4、rb_tree的元素操作

1)插入元素的插入操作 insert_equal(),插入的值可以是重复的。

[cpp] view plaincopy
  1. // 安插新值;節點鍵值允許重複。
  2. // 注意,傳回值是一個 RB-tree 迭代器,指向新增節點
  3. template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
  4. typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
  5. rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::<strong>insert_equal</strong>(const Value& v)
  6. {
  7. link_type y = header;
  8. link_type x = root(); // 從根節點開始
  9. while (x != 0) {      // 從根節點開始,往下尋找適當的安插點
  10. y = x;
  11. x = key_compare(KeyOfValue()(v), key(x)) ? left(x) : right(x);
  12. // 以上,遇「大」則往左,遇「小於或等於」則往右
  13. }
  14. return __insert(x, y, v);
  15. }

2)插入元素的插入操作 insert_unique(),插入的值不能重复的。

[cpp] view plaincopy
  1. // 安插新值;節點鍵值不允許重複,若重複則安插無效。
  2. // 注意,傳回值是個pair,第一元素是個 RB-tree 迭代器,指向新增節點,
  3. // 第二元素表示安插成功與否。
  4. template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
  5. pair<typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator, bool>
  6. rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::<strong>insert_unique</strong>(const Value& v)
  7. {
  8. link_type y = header;
  9. link_type x = root(); // 從根節點開始
  10. bool comp = true;
  11. while (x != 0) {      // 從根節點開始,往下尋找適當的安插點
  12. y = x;
  13. comp = key_compare(KeyOfValue()(v), key(x)); // v 鍵值小於目前節點之鍵值?
  14. x = comp ? left(x) : right(x);  // 遇「大」則往左,遇「小於或等於」則往右
  15. }
  16. // 離開 while 迴圈之後,y 所指即安插點之父節點(此時的它必為葉節點)
  17. iterator j = iterator(y);   // 令迭代器j指向安插點之父節點 y
  18. if (comp) // 如果離開 while 迴圈時 comp 為真(表示遇「大」,將安插於左側)
  19. if (j == begin())   // 如果安插點之父節點為最左節點
  20. return pair<iterator,bool>(__insert(x, y, v), true);
  21. // 以上,x 為安插點,y 為安插點之父節點,v 為新值。
  22. else    // 否則(安插點之父節點不為最左節點)
  23. --j;  // 調整 j,回頭準備測試...
  24. if (key_compare(key(j.node), KeyOfValue()(v)))
  25. // 小於新值(表示遇「小」,將安插於右側)
  26. return pair<iterator,bool>(__insert(x, y, v), true);
  27. // 進行至此,表示新值一定與樹中鍵值重複,那麼就不該插入新值。
  28. return pair<iterator,bool>(j, false);
  29. }

3)真正的插入操作执行程序 __insert()

[cpp] view plaincopy
  1. template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
  2. typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator
  3. rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::
  4. __insert(base_ptr x_, base_ptr y_, const Value& v) {
  5. // 參數x_ 為新值安插點,參數y_ 為安插點之父節點,參數v 為新值。
  6. link_type x = (link_type) x_;
  7. link_type y = (link_type) y_;
  8. link_type z;
  9. // key_compare 是鍵值大小比較準則。應該會是個 function object。
  10. if (y == header || x != 0 || key_compare(KeyOfValue()(v), key(y))) {
  11. z = create_node(v);  // 產生一個新節點
  12. left(y) = z;          // 這使得當 y 即為 header時,leftmost() = z
  13. if (y == header) {
  14. root() = z;
  15. rightmost() = z;
  16. }
  17. else if (y == leftmost())   // 如果y為最左節點
  18. leftmost() = z;               // 維護leftmost(),使它永遠指向最左節點
  19. }
  20. else {
  21. z = create_node(v);     // 產生一個新節點
  22. right(y) = z;               // 令新節點成為安插點之父節點 y 的右子節點
  23. if (y == rightmost())
  24. rightmost() = z;              // 維護rightmost(),使它永遠指向最右節點
  25. }
  26. parent(z) = y;        // 設定新節點的父節點
  27. left(z) = 0;      // 設定新節點的左子節點
  28. right(z) = 0;         // 設定新節點的右子節點
  29. // 新節點的顏色將在 __rb_tree_rebalance() 設定(並調整)
  30. __rb_tree_rebalance(z, header->parent);    // 參數一為新增節點,參數二為 root
  31. ++node_count;     // 節點數累加
  32. return iterator(z);   // 傳回一個迭代器,指向新增節點
  33. }

4)调整RB_tree (旋转及改变颜色)

任何插入操作,于节点插入完毕后,都要做一次调整操作,将树的状态调整到符合RB_tree的要求。

__rb_tree_rebalance()是具备如此能力的一个全局函数:

[cpp] view plaincopy
  1. inline void
  2. __rb_tree_rebalance(__rb_tree_node_base* x, __rb_tree_node_base*& root)
  3. {
  4. x->color = __rb_tree_red;      // 新節點必為紅
  5. while (x != root && x->parent->color == __rb_tree_red) { // 父節點為紅
  6. if (x->parent == x->parent->parent->left) { // 父節點為祖父節點之左子節點
  7. __rb_tree_node_base* y = x->parent->parent->right;   // 令y 為伯父節點
  8. if (y && y->color == __rb_tree_red) {      // 伯父節點存在,且為紅
  9. x->parent->color = __rb_tree_black;       // 更改父節點為黑
  10. y->color = __rb_tree_black;              // 更改伯父節點為黑
  11. x->parent->parent->color = __rb_tree_red;  // 更改祖父節點為紅
  12. x = x->parent->parent;
  13. }
  14. else {    // 無伯父節點,或伯父節點為黑
  15. if (x == x->parent->right) { // 如果新節點為父節點之右子節點
  16. x = x->parent;
  17. __rb_tree_rotate_left(x, root); // 第一參數為左旋點
  18. }
  19. x->parent->color = __rb_tree_black;   // 改變顏色
  20. x->parent->parent->color = __rb_tree_red;
  21. __rb_tree_rotate_right(x->parent->parent, root); // 第一參數為右旋點
  22. }
  23. }
  24. else {  // 父節點為祖父節點之右子節點
  25. __rb_tree_node_base* y = x->parent->parent->left; // 令y 為伯父節點
  26. if (y && y->color == __rb_tree_red) {      // 有伯父節點,且為紅
  27. x->parent->color = __rb_tree_black;       // 更改父節點為黑
  28. y->color = __rb_tree_black;              // 更改伯父節點為黑
  29. x->parent->parent->color = __rb_tree_red;  // 更改祖父節點為紅
  30. x = x->parent->parent;    // 準備繼續往上層檢查...
  31. }
  32. else {    // 無伯父節點,或伯父節點為黑
  33. if (x == x->parent->left) {   // 如果新節點為父節點之左子節點
  34. x = x->parent;
  35. __rb_tree_rotate_right(x, root);  // 第一參數為右旋點
  36. }
  37. x->parent->color = __rb_tree_black;   // 改變顏色
  38. x->parent->parent->color = __rb_tree_red;
  39. __rb_tree_rotate_left(x->parent->parent, root); // 第一參數為左旋點
  40. }
  41. }
  42. } // while 結束
  43. root->color = __rb_tree_black; // 根節點永遠為黑
  44. }

上述的调整函数需要左旋右旋

__rb_tree_rotate_left():左旋

[cpp] view plaincopy
  1. // 以下都是全域函式:__rb_tree_rotate_left(), __rb_tree_rotate_right(),
  2. // __rb_tree_rebalance(), __rb_tree_rebalance_for_erase()
  3. // 新節點必為紅節點。如果安插處之父節點亦為紅節點,就違反紅黑樹規則,此時必須
  4. // 做樹形旋轉(及顏色改變,在程式它處)。
  5. inline void
  6. __rb_tree_rotate_left(__rb_tree_node_base* x, __rb_tree_node_base*& root)
  7. {
  8. // x 為旋轉點
  9. __rb_tree_node_base* y = x->right; // 令y 為旋轉點的右子節點
  10. x->right = y->left;
  11. if (y->left !=0)
  12. y->left->parent = x;      // 別忘了回馬槍設定父節點
  13. y->parent = x->parent;
  14. // 令 y 完全頂替 x 的地位(必須將 x 對其父節點的關係完全接收過來)
  15. if (x == root)                    // x 為根節點
  16. root = y;
  17. else if (x == x->parent->left)  // x 為其父節點的左子節點
  18. x->parent->left = y;
  19. else                          // x 為其父節點的右子節點
  20. x->parent->right = y;
  21. y->left = x;
  22. x->parent = y;
  23. }

__rb_tree_rotate_right():右旋

[cpp] view plaincopy
  1. // 新節點必為紅節點。如果安插處之父節點亦為紅節點,就違反紅黑樹規則,此時必須
  2. // 做樹形旋轉(及顏色改變,在程式它處)。
  3. inline void
  4. __rb_tree_rotate_right(__rb_tree_node_base* x, __rb_tree_node_base*& root)
  5. {
  6. // x 為旋轉點
  7. __rb_tree_node_base* y = x->left;  // y 為旋轉點的左子節點
  8. x->left = y->right;
  9. if (y->right != 0)
  10. y->right->parent = x;     // 別忘了回馬槍設定父節點
  11. y->parent = x->parent;
  12. // 令 y 完全頂替 x 的地位(必須將 x 對其父節點的關係完全接收過來)
  13. if (x == root)                    // x 為根節點
  14. root = y;
  15. else if (x == x->parent->right) // x 為其父節點的右子節點
  16. x->parent->right = y;
  17. else                          // x 為其父節點的左子節點
  18. x->parent->left = y;
  19. y->right = x;
  20. x->parent = y;
  21. }
from: http://blog.csdn.net/cyh_24/article/details/8068735

STL的红与黑--rb_tree红黑树相关推荐

  1. STL源码剖析---红黑树原理详解下

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584       算法导论书上给出的红黑树的性质如下,跟STL源码 ...

  2. C++进阶——STL源码之红黑树(_Rb_tree)

    STL源码之红黑树 红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组:红黑树是在1972年由Rudolf Bayer发明的, ...

  3. STL 源码分析: RB_tree 红黑树(三) 插入和查找

    不管什么样的插入,在插入新的节点后都考虑红黑树的四条约束是否被破坏,于是需要通过更改节点的颜色和子树的形状来使得红黑树的四条性质重新获得满足. 首先介绍两个旋转函数:左旋和右旋. 我们先看两个函数的原 ...

  4. C++ rb_tree红黑树

    在 STL 编程中,容器是我们经常会用到的一种数据结构,容器分为序列式容器和关联式容器. 两者的本质区别在于:序列式容器是通过元素在容器中的位置顺序存储和访问元素,而关联容器则是通过键 (key) 存 ...

  5. STL源码剖析---红黑树原理详解上

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7740956 一.红黑树概述 红黑树和我们以前学过的AVL树类似,都是在进 ...

  6. STL浅析 RB-tree(红黑树)

    RB-tree(红黑树)是平衡二叉搜索树.RB-tree满足二叉搜索树的规则之外,还遵循以下特性: 每个节点不是红色就是黑色. 根节点为黑色. 如果节点为红色,其子节点必须为黑色. 任意一个节点到到N ...

  7. STL源码剖析---红黑树原理详解

    红黑树概述 红黑树都是在进行插入和删除时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能.红黑树追求的时局部平衡而不是AVL树中的非常严格的平衡. 所谓红黑树,不仅是一个二叉搜索树,而且必须满 ...

  8. STL源码剖析 关联式容器 红黑树

    概念 红黑树不仅仅是一个二叉树,必须满足如下条件 1,每个节点不是红色就是黑色 (深色底纹为黑色,浅色底纹为红色) 2,根节点是黑色的 3,如果节点为红,其子节点必须为黑色的 4,任一节点至NULL( ...

  9. 红黑树分为红和黑有什么好处_彻底搞懂红黑树

    红黑树和c++ 虚拟继承内存分布 几乎成了我的死敌,因为完全没用过,所以导致每次看懂了之后都忘了(也许不是真的看懂了,有些关键性的东西没理解透),这次准备把这两个难题(其实也不难)仔细看懂,然后再写一 ...

最新文章

  1. 全球科技大会鸿蒙,华为开发者大会:全球瞩目的“鸿蒙”面子和里子大格局
  2. UIButton设置 textAlignment 属性的方法
  3. 因退休太无聊,Python创始人加入微软!
  4. html table相关标签和属性
  5. html5发展前景-兄弟连,IT兄弟连 HTML5教程 HTML5的曲折发展过程 HTML5的诞生
  6. 给 JDK 官方提了一个 Bug,结果...
  7. Ztree勾选节点后取消勾选其父子节点
  8. Express の 文件下载
  9. MATLAB 2018a Mac版安装激活教程
  10. Mac教程——创建txt文件、设置新建txt的快捷键方法
  11. 对自然数e的理解,推导(基础)
  12. 物联网卡开启养老新模式
  13. 性别收入差距=歧视?Oaxaca-Blinder分解方法
  14. 无线路由实战(一):增强无线wifi信号和加速wifi的十一种方法
  15. openfoam 源代码解析
  16. 使用React Native创建乘车预订应用程序
  17. tcpdf addfont.php,PHP5 tcpdf 6.2.13 插件 tcpdf是一個用於快速生成PDF文件的PHP5函數包 - 下载 - 搜珍网...
  18. 小天软件园程序源码 一款纯发布软件程序
  19. 主机屋延长免费空间使用期限攻略
  20. 【蓝桥杯】【python】兰顿蚂蚁

热门文章

  1. 任正非:我若贪生怕死,何来让你们去英勇奋斗
  2. IBM在人工智能方面的新进展,理解谈话情景和感知情绪
  3. 刘强东:猪飞到天疯狂了十几秒 但摔下死得更快
  4. 深入理解分布式技术 - BASE 理论
  5. Quartz-Job 详解
  6. Spring MVC-使用Spring Tool Suite IDE搭建Spring MVC开发环境
  7. Java-工具类之ZIP压缩解压
  8. 传统的http请求存在那些缺点
  9. 人工智能:CNN过时了,有人提出GNN
  10. 加载pdf_Java 插入附件到PDF文档