When I looked at the kernel code in the first half of 2014, the process scheduling used the RB tree. Now, when I analyzed the STL source code, I found that set and MAP also used this data structure, this illustrates the wide application of rbtree, so I spent two days reading it and explained it in three parts. First of all, I want to explain the basic concepts of the red and black trees, next, describe the RB tree iterator in STL, and finally describe the implementation of the RB tree container in STL.
I. Basic concepts of red/black trees
The red/black tree is a type of balanced binary search tree (AVL Tree exists in the balanced binary search tree). In addition to the conditions of the binary search tree, you should also buy the following four conditions.
1) each node is either red or black;
2) The root node is black;
3) if the node is red, the child node is black (so the parent node of the newly added node is black)
4) any path from any node to null (tail end of the tree) must contain the same number of black nodes (so the newly added nodes are red)
If a node is inserted according to the Binary Search Tree rule and the node fails to meet the preceding requirements, you must adjust the color and rotate the tree.
The following is a case study. After inserting a node, I found that the node fails to meet the requirements and how to adjust the color and rotate the tree.
In the red-black tree, we insert four nodes 3, 8, 35, and 75. After the insertion, it must be red first. In this case, these four insert operations violate Condition 3 (the child node of the red node is black). The four points above represent the four middle nodes, and the figure is representative, next we will analyze the situation:
Scenario 1:
Insert Node 3, as shown in:
The primary node of Node 3 is a black node (if it is null, it is black), and node 3 is an external insert. In this case, you need to perform a right-hand operation:
Here, the right-hand side is to drop the grandpa node down by a layer and raise the parent node to a layer because the parent node is red. According to Condition 3, the child node of the red node is black, therefore, the color of the parent node is changed to black. According to condition 4, the color of the fallen Grandpa node is changed to red to meet the condition of the Binary Search Tree, that is, the value of the Left subtree is smaller than/greater than the value of the right subtree. Therefore, the left subtree of the parent node is moved to the left subtree Of The Grandmaster node.
Case 2: The inserted uncle node (also known as Uncle node) on node 8 and node 8 are black (null is regarded as black), and inserted on the inner side is:
As shown in figure, after 8 is raised to 5, the color of 8 is adjusted to black to meet the condition 3, hand over the left subtree of 8 to the right subtree of 5 to meet the condition of the binary search tree, then adjust the grandpa node to red and then to the second, then, right-handed (to reduce the height difference between left and right subtree ).
Case 3: insert node 75. Then, the primary node is red and the primary node is inserted as the outer node:
At this time, the grandfather node 85 has no right-hand point. After the right-hand node, it is OK because the former grandfather node is black at this time;
Scenario 4: Insert a node with a node value of 35. The difference with scenario 3 is that after the adjustment, the former grandfather node is red, so you have to continue to make the same rotation and color adjustment, see the following figure until the parent and child are no longer in Red:
OK. The following describes how to insert a node to a cluster.
II. Implementation of the red/black tree iterator
Here I paste the Code directly:
typedef bool __rb_tree_color_type;typedef __rb_tree_color_type __rb_tree_red = false;typedef __rb_tree_color_type __rb_tree_black = true;struct __rb_tree_node_base{typedef __rb_tree_color_typecolor_type;typedef __rb_tree_node_base*base_ptr;color_type color;base_ptr parent;base_ptr left;base_ptr right;static base_ptr minimum (base_ptr x) {while(x->left != 0)x = x->left;return x;}static base_ptr maximum(base_ptr x) {while (x->right != 0)x = x->right;return x;}};template <class Value>struct __rb_tree_node: public __rb_tree_node_base {typedef __rb_tree_node<Value>*link_type;Value value_field;};struct __rb_tree_base_iterator{typedef__rb_tree_node_base::base_ptr base_ptr;typedefbidirectional_iterator_tagiterator_category;typedefptrdiff_tdifference_type;base_ptrnode;void increment() {if (node->right != 0) {node = node->right;while (node->left != 0)node = node->left;}else {base_ptr y = node->parent; while ( node == y->right) {node = y;y = y->parent;}if (node->right != y)node = y;}}void decrement() {if( node->color == __rb_tree_red && node->parent->parent == node) {node = node->left;}else if (node->left != 0) {node = node->left;while ( node->right != 0) {node = node->right;}}else {base_ptr y = node->parent;while (node == y->left) {node = y;y = y->parent;}node = y;}}};template <class Value , class Ref , class Ptr>struct __rb_tree_iterator: public __rb_tree_base_iterator{typedef Value value_type;typedef Ref referece;typedef Ptr pointer;typedef __rb_tree_iterator<Value , Value & , Value *> iterator;typedef __rb_tree_iterator<Value , const Value & , const Value*> const_iterator;typedef __rb_tree_iterator<Value , Ref , Ptr> self;typedef __rb_tree_node<Value>* link_type;__rb_tree_iterator() {}__rb_tree_iterator(link_type x) { node_offset = x ;}__rb_tree_iterator(const iterator &it) { node = it.node; }referece operator*() const { return link_type(node)->value_field ;}referece operator->() const { return &(operator*());}self& operator++() {increment();return *this;}self operator++(int) {self tmp = *this;increment();return tmp;}self& operator--() {decrement();return *this;}self operator--() {self tmp = *this;decrement();return tmp;}};
Here I want to analyze the function increment (), decrement () and increment are similar, so here I will only talk about Increment
void increment() {if (node->right != 0) {node = node->right;while (node->left != 0)node = node->left;}else {base_ptr y = node->parent;while ( node == y->right) {node = y;y = y->parent;}if (node->right != y)node = y;}}
Here, increment is used to direct a node to a node greater than it. The value of the right subtree node of a node is greater than that of a node, the smallest node in the right subtree is the leftmost node in the right subtree;
If the right subtree is empty, it can only be traced back. If the node is the right child of node-> parent, the node value is greater than the node-> parent value, if it is the left child of node-> parent, it is smaller than parent. The next child node that is greater than node is the parent node of the Left subtree of node.
(The Last Judgment is to deal with the special relationship between the root node of the RB-tree and the header)
Iii. Implementation of the red/black tree
The implementation code is long and the code logic is not difficult. It is not difficult to analyze the Code against the above example. Here I will only talk about the Function insert_unique, although the logic is not difficult;
The parent of the data member header is root, left is leftmost, and right is rightmost, which is an implementation technique.
template <class Key , class Value , class KeyOfValue , class Compare , class Alloc = alloc>class rb_tree{protected:typedef void* void_pointer;typedef __rb_tree_node_base *base_ptr;typedef __rb_tree_node<Value>rb_tree_node;typedef simple_alloc<rb_tree_node , Alloc>rb_tree_node_allocator;typedef __rb_tree_color_type color_type;public:typedef Key key_type;typedef Value value_type;typedef const value_type* const_iterator;typedef value_type&reference;typedef const value_type&const_reference;typedef rb_tree_node*link_type;typedef size_t size_type;typedef ptrdiff_tdifference_type;public:link_type get_node() {return rb_tree_node::allocate();}void put_node(link_type p) {rb_tree_node::deallocate();}link_type create_node(const value_type& x) {link_type tmp = get_node();construct(&tmp->value_field , x)return tmp;}link_type clone_node(link_type x) {link_type tmp = create_node(x->value_field);tmp->color = x->color;tmp->left = 0;tmp->right = 0;return tmp;}void destroy_node(link_type p) {destroy(&p->value_field);put_node(p);}protected:size_typenode_count;link_typeheader;Comparekey_compare;link_type&root() const { return (link_type&) header->parent; }link_type&leftmost() const { return (link_type&) header->left; }link_type&rightmost() const { return (link_type&) header->right;}staticlink_type& left(link_type x){return (link_type&) x->left; }staticlink_type& right(link_type x){return (link_type&)x->right;}staticlink_type& parent(link_type x) {return (link_type&)x->parent;}staticreference value(link_type x){returnx->value_field;}staticconst Key&key(link_type x){returnKeyOfValue() (value(x));}staticcolor_type& color(link_type x){return(color_type&) (x->color);}staticlink_type& left(base_ptr x) {return (link_type&) x->left; }staticlink_type& right(base_ptr x) {return (link_type&)x->right;}staticlink_type& parent(base_ptr x) {return (link_type&)x->parent;}staticreference value(base_ptr x){returnx->value_field;}staticconst Key&key(base_ptr x){returnKeyOfValue() (value(x));}staticcolor_type& color(base_ptr x){return(color_type&) (x->color);}staticlink_type minimum(link_type x) {return (link_type) __rb_tree_node_base::minimum(x);}staticlink_type maximum(link_type x) {return (link_type) __rb_tree_node_base::maximum(x);}public:typedef__rb_tree_iterator<value_type , reference , pointer>iterator;private:iterator __insert(base_ptr x , base_ptr y, const value_type& v);link_type__copy(link_type x , link_type p);void __erase(link_typex);void init() {header = get_node();color(header) = __rb_tree_red;root() = 0;leftmost() = header;rightmost()= header;}public:rb_tree(const Compare& comp = Compare()): node_count(0) , key_compare(comp) {init();}~rb_tree() {clear();put_node(header);}rb_tree<Key , Value , KeyOfValue , Compare , Alloc>&operator= (const rb_tree<Key , Value , KeyOfValue , Compare , Alloc>& x);Compare key_comp() const {return key_compare; }iterator begin() {return leftmost(); }iterator end() {returnheader; }bool empty() {returnnode_count == 0; }size_typesize()const {return node_count;}size_typemax_size()const {returnsize_type(-1);}public:pair<iterator , bool> inset_unique(const value_type& x);iterator insert_equal(const value_type& x);};template <class Key , class Value , class KeyOfValue , class Compare , class Alloc = alloc>typename rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::iteratorrb_tree<Key , Value , KeyOfValue , Compare , Alloc>::insert_equal(const Value& x){link_type y = header;link_type x = root();while ( x != 0 ) {y = x;x = key_compare(KeyOfValue()(v) , key(x)) ? left(x) : right(x);} return __insert(x , y ,v);}template <class Key , class Value , class KeyOfValue , class Compare , class Alloc = alloc>template <class Key , class Value , class KeyOfValue , class Compare , class Alloc = alloc>typename rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::iteratorrb_tree<Key , Value , KeyOfValue , Compare , Alloc>::__insert(base_ptr x_ , base_ptr y_ , const Value& v){link_typex = (link_type) x_;link_typey = (link_type)y_;link_typez;if ( y == header || x != 0 || key_compare(KeyOfValue()(v) , key(v))) {z = create_node(v);left(y) = z;if ( y == header) {root() = z;rightmost() = z;}else if (y == leftmost())leftmost = z;}else {z = create_node(v);right(y) = z;if ( y == rightmost() )rightmost() = z;}parent(z) = y;left(z)= 0;right(z)= 0;__rb_tree_rebalance(z , header->parent);++node_count;return iterator(z);}inline void __rb_tree_rebalance( __rb_tree_node_base* x , __rb_tree_node_base* &root){x->color = __rb_tree_red;while ( x != root && x->parent->color == __rb_tree_red ) {if ( x->parent == x->parent->parent->left) {__rb_tree_node_base* y = x->parent->parent->right;if ( y && y->color == __rb_tree_red ) {x->parent->color = __rb_tree_black;y->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;x = x->parent->parent;}else {if ( x == x->parent->right) {x = x->parent;__rb_tree_rotate_left (x , root);}x->parent->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;__rb_tree_rotate_right (x->parent->parent , root);}}else {__rb_tree_node_base* y = x->parent->parent->right;if ( y && y->color == __rb_tree_red) {x->parent->color = __rb_tree_black;y->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;}else {if (x == x->parent->left ) {x = x->parent;__rb_tree_rotate_right(x , root);}x->parent->color = __rb_tree_black;x->parent->parent->color = __rb_tree_red;__rb_tree_rotate_left(x->parent->parent , root);}}}root->color = __rb_tree_black;}inline void __rb_tree_rotate_left(__rb_tree_node_base* x , __rb_tree_node_base* &root){__rb_tree_node_base* y = x->right;x->right = y->left;if (y->left != 0) y->left->parent = x;if (x == root) root = y;else if ( x == x->parent->left )x->parent->left = y;elsex->parent->right = y;y->left = x;x->parent = y;}inline void __rb_tree_rotate_rigth(__rb_tree_node_base* x , __rb_tree_node_base* &root){__rb_tree_node_base* y = x->left;x->left = y->right;if (y->right != 0) y->right->parent = x;if (x == root) root = y;else if ( x == x->parent->left )x->parent->left = y;elsex->parent->right = y;y->right = x;x->parent = y;}
The insert_unique function ensures that the inserted key values cannot be duplicated.
Typename rb_tree <key, value, keyofvalue, compare, alloc >:: iteratorrb_tree <key, value, keyofvalue, compare, alloc >:: insert_unique (const value & X) {link_type y = header; link_typex = root (); boolcomp = true; while (X! = 0) {// start from the root node and find the appropriate insertion point y = x; comp = key_compare (keyofvalue () (v), key (x )); X = comp? Left (x): Right (x); // when it is big, it goes to the left. If it is less than or equal to it, it goes to the right.} // after it leaves, Y is the parent node of the insertion point, in this case, it must be leaf node iterator J = iterator (y); If (COMP) {// If the while loop is left, the comp is true, if (j = begin () {// The parent node of the insertion point is the leftmost node, return pair <iterator, bool> (_ insert (X, Y, v), true);} else -- J ;} if (key_compare (Key (J. node), keyofvalue () (v) returnpair <iterator, bool> (_ insert (X, Y, v), true); Return (pair <iterator, bool>, false );}
If the parent node is not the leftmost node, -- J points J to the previous node smaller than the parent node and compares it with the key value of V, non-equality indicates that there are no duplicates, because the insertion point is left child and must be smaller than the parent node, then it is compared with a node smaller than the parent node (V must be greater than or equal to this value). If it is not equal, it is inserted;
In addition, if the insertion point is the right child of the parent node y, the right child is greater than or equal to Y, then the size is compared with Y. If the insertion point is not equal to Y, the right child is inserted.
Here, I only noted the code that confused me when I read the code. If anything is wrong, please correct me. Thank you, O) O Haha ~
Stl rb tree (Red/black tree) Analysis