In practice, we do not directly use the Binary Search Tree, because the performance of the Binary Search Tree is heavily dependent on the insertion sequence of elements, especially when an element is inserted in an ascending manner, in this case, the binary search tree will become a linked list. In practical applications, we use the "balanced" binary search tree, including the AVL, red, black, and AA trees, the most commonly used is the red/black tree (the underlying implementation of the associated containers in STL is the red/black tree used), which ensures that the time complexity of basic dynamic set operations in the worst case is O (lgn)
The red/black tree adds a color attribute on each node, which can be red or black. Due to the nature of the red/black tree, no path can grow twice as long as other paths, therefore, it is "approximately balanced", but the red/black tree usually leads to a good balance. experience tells us that the average search efficiency of the red/black tree is equal to that of the AVL Tree.
The nature of the red/black tree:
1. Each node is either red or black;
2. The root node is black.
3. Each leaf node (null) is black.
4. If a node is red, its two child nodes are black.
5. For each node, the simple path from this node to all its descendant leaf nodes contains the same number of black nodes
Implementation Policy of the red/black tree:
Add sentinel: T. nil stands for nil, where T. nil is an object with the same attributes as a common node. All pointers to nil are directed to T. nil pointer replacement (mainly because nil cannot be colored)
We can add a sentry for each leaf node like figure (a), so that each Nil's parent node has a good definition, but it will waste a lot of space, so we only use one sentint. nil represents all nil: the parent node of all leaf nodes and root nodes.
We may wonder why we need to define a T. Nil? It is expressed by null. Is it black by default? STL does not have this sentry, but STL does not have a delete operation ------ as far as I know, T. the biggest role of Nil is the delete operation-its parent node can be changed to any node, which is used to trace back its parent node.
In the implementation of the Red-black tree, the height of the subtree can be changed, that is, the operation that can make it different from the general binary search tree is: rotation. Rotation can change the height of the sub-tree to maintain the property of the red/black tree:
The left-hand (X, Y are not T. Nil) is used to increase y and decrease X. It is mainly used to exchange parent-child relationships:
Left-rotate (t, x) y = x. Right X. Right = Y. Left if y. Left! = T. nil y. left. P = x Y. P = x. P if X. P = T. nil // X is the root T. root = y else if x = x. p. left X. p. left = y else X. p. right = y. left = x. P = y
Right hand:
RIGHT-ROTATE(T,x) y=x.left x.left=y.right if y.right!=T.nil y.right.p=x y.p=x.p if x.p=T.nil T.root=y elseif x==x.p.left x.p.left=y else x.p.right=y y.right=x x.p=y
Insert operation:
Insert operations are divided into two parts: insert and adjust;
If the nodes to be inserted are all red, the properties of the red and black trees are 1, 3, and 5 unchanged. When the original tree is empty, the properties of the tree are changed. 2. The nature of the tree may be changed. 4;
The subsequent adjustment is to make the properties 2 and 4 retained.
RB-INSERT (T, Z) y = T. Nil x = T. Root while X! = T. nil y = x if z. key <X. key x = x. left else x = x. right Z. P = y if y = T. nil T. root = z elseif Z. key <Y. key y. left = z else y. right = z // The following section is more than the common Binary Search Tree Z. left = T. nil Z. right = T. nil Z. color = Red RB-INSERT-FIXUP (T, Z) // Adjustment
The principle of adjustment is to move the nodes that break the rules up as much as possible. In the worst case, if you move the nodes up to the root node, you only need to set the root node to black.
The adjustment occurs in the following way: when the parent node of the inserted node is a red knot, the grandfather node must be black and the uncle node is unknown:
In this case, there are six situations. The following three situations are analyzed when the parent node of the inserted node is the left child of the grandfather node:
Case1: The primary node is red (the insertion node is left-side Insertion-External insertion, or right-side Insertion-interpolation)
At this time, as long as the C times are red, B, d is changed to black, and the Blak-height remains unchanged, the only node that may violate the nature is C, therefore, the node that breaks the rule is moved up.
Case2: The uncle node is black, and the inserted node is insert on the right --- interpolation:
We will change the inner side to the outer side to insert the parent node A of the inserted node to the left side. At this time, we will point Z to B and change it to the outer side, that is, the third case.
Case3: The uncle node is black, and the inserted node is left-side inserted --- external inserted
At this time, C is used as the pivot, right-handed, and B is changed to black, and C is changed to red.
RB-INSERT-FIXUP (T, Z) while Z. p. color = red if z. P = z. p. p. left y = z. p. p. right // uncle node if y. color = red // case1 Z. p. color = black y. color = black Z. p. p. color = Red z = z. p. P elseif z = z. p. right // case2 z = z. P left-rotate (T, Z) // insert it to the outside and execute case3 Z. p. color = black Z. p. p. color = Red Right-rotate (T, Z. p. p) else // Insert the parent node of the node. For the right child of the grandfather node, replace [left] with [right] T. root. color = black
The delete operation can be divided into two parts: delete and adjust
The first step is to delete the Helper Program-transplant. Replace the U-root subtree with the V-root subtree, which is usually applicable to the unique child knots of U.
RB-TRANSPLANT(T,u,v) if u.p==T.nil T.root=v elseif u==u.p.left u.p.left=v else u.p.rigth=v v.p=u.p
Delete programs from the same binary search tree. [See Binary Search Tree code parsing]
Adjustment:
Focus on-Y: the node to be deleted from the tree or moved to the node in the tree (that is, the successor to the original node to be deleted)
If y is red, it is deleted directly without violating the nature;
If y is black, if y is the deleted node, the number of black nodes in any simple path containing y is less than 1. If Y is a mobile node, the same applies;
Here we adopt the following strategy:
If X is an element that replaces the position after deletion or movement of Y, there is still a heavy black color for X, but the problem now becomes: X is neither red nor black, violating Nature 1.
When X is the left child of its parent node:
Case0:
When X is single-weight black and single-weight red, the task is completed if X is directly set to black;
Case1: X is double black, and X's brother node W is red. At this time, X's parent node must be black:
What we need to do at this time is: change the color of B to red with the parent node B of X, and change the color of W to black. In this case, except for property 1, other properties are maintained.
<After case1, the brother node of X is Black>
Case2: X is double black, X's brother node W is black, and W's two child nodes are black:
In this case, the color of W turns red, removing the heavy black of X, and adding a heavy black to the X parent node. At this time, the only node that violates the nature is the parent node of X.
Case3: X is double black, X's brother node W is black, W's left child is black, and right child is Red:
Now we change W right, and C to the new W, C to black, d to red, and then to the fourth case.
Case4: X is double black, Brother node W is black, and W's right child is Red:
In this case, you can remove the heavy black -- of X --.
The RB-DELETE-FIXUP while X! = T. root and X. color = black // at this time, it is a two-digit black if x = x. p. left // when X is the left child of the parent node W = x. p. right // X's sibling node if W. color = red // case1 W. color = black X. p. color = Red left-rotate (t, x. p) W = x. p. rightif W. left. color = black and W. right. color = black // case2 W. color = Red X = x. pelseif W. right. color = black // case3 W. left. color = Black W. color = Red Right-rotate (T, W) W = x. p. right // case4 W. color = x. p. color X. p. color = Black W. right. color = Black left-rotate (t, x. p) x = T. root else left and right interchange X. color = bblack // case0
The following is a copy of the STL red/black tree. The simple version of The Red/black tree expands the binary search tree:
// The following uses the STL version of the Red-black tree. The simple version of the Red-black tree is basically the same as the binary search tree, except for the trouble of inserting and deleting. # Include "myconstruct. H "# include" myiterator. H "# include" mymemory. H "# include <utility> // color typedef bool _ rb_tree_color_type; const _ rb_tree_color_type _ rb_tree_red = false; // the red color is 0 const _ rb_tree_color_type _ rb_tree_black = true; // Black: 1 // node Structure template <typename value> struct _ rb_tree_node {typedef _ rb_tree_color_type color_type; typedef _ rb_tree_node <value> node_type; color_type color; value value_field; node_type * pa Rent; node_type * left; node_type * right; static node_type * minimum (node_type * X) {While (X-> left! = 0) x = x-> left; return X;} static node_type * maximum (node_type * X) {While (X-> right! = 0) x = x-> right; return x ;}; // iterator design: Template <typename value, typename ref, typename PTR> struct _ struct {typedef incluiterator_category; typedef size_t difference_type; typedef _ rb_tree_node <value> node_type; typedef value value_type; typedef ref reference; 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; node_type * node; // contact container _ rb_tree_iterator () {} _ rb_tree_iterator (node_type * X) {node = x;} _ rb_tree_iterator (const iterator & IT) {node = it. node;} reference operator * () const {return node-> value_field;} pointer operator-> () const {return & (operator *());} self & operator ++ () {increment (); return * This;} self operator ++ (INT) {self TMP = * This; in Crement (); Return TMP;} self & operator -- () {decrement (); return * This;} self operator -- (INT) {self TMP = * this; decrement (); Return TMP;} bool operator = (const self & X) const {return X. node = node;} bool Operator! = (Const self & X) const {return X. node! = Node;} PRIVATE: // auxiliary program void increment (); // subsequent void decrement (); // precursor}; // forward/* returns the Middle-order time, the structure of the Binary Search Tree allows us to get O (h) without any keyword comparison: * case1: if the right subtree of X is not empty, then Y is the smallest element of the right subtree of x * case2: if the right subtree of X is empty: * case1 ': If X is the left child of the parent node, then the successor of X is the parent node * case2': If X is the right child of parent node y, search for such a node Z to make X, Y is the left subtree of z */template <typename value, typename ref, typename PTR> void _ rb_t Ree_iterator <value, ref, PTR >:: increment () {If (node-> right! = 0) {// case1node = node_type: Minimum (node-> right);} else {// case2 // case1 ': node_type * Y = node-> parent; // case2': While (node = Y-> right) {node = y; y = Y-> parent;} If (node-> right! = Y) node = y ;}/// sums/* returns the Ordinal Time, X's precursor: O (h) * case1: X has a left subtree, then the precursor of X is the maximum value of the Left subtree of X. * case2: X has no left subtree * case1 ': X is the right child of its parent node Y. Then the precursor is y * case2 ': X is the left child of its parent node Y. it searches for the ancestor Z so that the subtree where X and Y are located is the right subtree of z */template <typename value, typename ref, typename PTR> void _ rb_tree_iterator <value, ref, PTR >:: decrement () {If (node-> color = _ rb_tree_red & node-> parent = node) // head Ernode = node-> right; else if (node-> left! = 0) {// case1node = node_type: Maximum (node-> left);} else {// case2 // case1 ': node_type * Y = node-> parent; // case2': While (node = Y-> left) {node = y; y = Y-> parent;} node = y ;}} // outputs // red/black tree template <typename key, typename value, typename keyofvalue, typename compare, typename alloc = alloc> class rb_tree {protected: typedef void * void_pointer; Typedef _ rb_tree_node <value> node_type; typedef simple_alloc <node_type, alloc> struct; typedef _ rb_tree_color_type color_type; public: typedef key key_type; typedef value value_type; typedef value_type * pointer; typedef const value_type * const_pointer; typedef value_type & reference; typedef const value_type & const_reference; typedef size_t size_type; typedef size_t difference_type; typedef _ RB _ Tree_iterator <value_type, reference, pointer> iterator; protected: // memory management // configure a node node_type * get_node () {return rb_tree_node_allocator: allocate ();} // release a node void put_node (node_type * P) {rb_tree_node_allocator: deallocate (p);} node_type * create_node (const value_type & X) {node_type * TMP = get_node (); construct (& TMP-> value_field, x); Return TMP; // you can use new directly, but you need to define the constructor} node_type * clone_node (node_type * X ); // copy a node Vo Id destroy_node (node_type * P) {destroy (& P-> value_field); // The Destructor put_node (p); // you can directly use Delete, but you need to define the Destructor} protected: size_type node_count; node_type * Header; // red, skillful Implementation of compare key_compare; // function object, used to compare node_type * & root () const {return header-> parent;} node_type * & leftmost () const {return header-> left;} node_type * & rightmost () const {return header-> right ;} // get the node value static node_type * & left (node_type * X) {return X-> left ;} Static node_type * & right (node_type * X) {return X-> right;} static node_type * & parent (node_type * X) {return X-> parent ;} static reference value (node_type * X) {return X-> value_field;} static const key & Key (node_type * X) {return keyofvalue () (value (x ));} static color_type & color (node_type * X) {return X-> color;} PRIVATE: iterator _ insert (node_type * X, node_type * y, const value_type & V ); void Init (); void clear (); Publ IC: // construct and analyze 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); Public: Compare key_comp () const {return key_compare;} iterator begin () {return leftmost ();} // iterator end () {return header;} // The minimum element of the red/black tree as the destination bool empty () const {return node_count = 0;} size_type size () const {return node_count;} size_type max_size () const {return s Ize_type (-1 );}//? Public: // duplicate node values are not allowed. STD: pair <iterator, bool> insert_unique (const value_type & X ); // allow repeated node values iterator insert_equal (const value_type & X); iterator find (const key & K) ;}; // template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> typename rb_tree <key, value, keyofvalue, compare, alloc >:: node_typ E * rb_tree <key, value, keyofvalue, compare, alloc >:: clone_node (node_type * X) {node_type TMP = create_node (X-> value_field ); TMP-> color = x-> color; TMP-> left = 0; TMP-> right = 0; return TMP;} // template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> void rb_tree <key, value, keyofvalue, compare, Al Loc>: Init () {// The left and right child nodes of the header point to their own header = get_node (); color (header) = _ rb_tree_red; root () = 0; leftmost () = header; rightmost () = header;} // your template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> typename rb_tree <key, value, keyofvalue, compare, alloc >:: iteratorrb_tree <key, value, keyofvalue, Co Mpare, alloc >:: insert_equal (const value & V) {node_type * Y = header; node_type * x = root (); While (X! = 0) {// start from the root node y = x; X = key_compare (keyofvalue () (v), key (x ))? Left (x): Right (x); // Returns _ insert (X, Y, v) when the value is less than or equal to the value of right ); // y is the parent node of the insertion point, and X is the insertion point} // template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> STD :: pair <typename rb_tree <key, value, keyofvalue, compare, alloc >:: iterator, bool> rb_tree <key, value, keyofvalue, compare, alloc >:: insert_unique (const Value & V) {node_type * Y = header; node_type * x = root (); bool comp = true; while (X! = 0) {Y = x; comp = key_compare (keyofvalue () (v), key (x); X = comp? Left (x): Right (x);} iterator J = iterator (y); If (COMP) {// when leaving while, comp is true, insert to left if (j = begin () // if the parent node of the insert point is the leftmost node return STD: pair <iterator, bool> (_ insert (X, y, v), true); else -- J;} If (key_compare (Key (J. node), keyofvalue () (v) // the new key value does not repeat the existing node value return STD: pair <iterator, bool> (_ insert (x, y, v), true); // return STD: pair <iterator, bool> (J, false);} // else );}//--------------------------------------------------------------------------- --------- Template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> typename rb_tree <key, value, keyofvalue, compare, alloc >:: keys <key, value, keyofvalue, compare, alloc >:_ insert (node_type * X, node_type * y, const value & V) {node_type * x_copy = x; node_type * y_copy = y; node_type * z; If (y = header | X! = 0 | key_compare (keyofvalue () (v), key (y) {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; Z-> color = _ rb_tree_red; _ rb_insert_fixup (z, header-> parent); ++ node_count; return iterator (z );}//---------------------------------------------------------------- Registrant template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> typename rb_tree <key, value, keyofvalue, compare, alloc >:: iteratorrb_tree <key, value, keyofvalue, compare, alloc >:: find (const key & K) {node_type * Y = header; node_type * x = root (); While (X! = 0) {If (! Key_compare (Key (x), k) // X greater than Ky = x, x = left (x); elsex = right (x );} iterator J = iterator (y); Return (j = end () | key_compare (K, key (J. node )))? End (): J;} // your template <typename key, typename value, typename keyofvalue, typename compare, typename alloc> void rb_tree <key, value, keyofvalue, compare, alloc >:: clear () {for (iterator it = begin (), next = ++ it; it! = End (); ++ next) {destroy_node (it. node); It = next ;}/// global function 1 -- left-side template <typename value> void _ rb_left_rotate (_ rb_tree_node <value> * X, _ rb_tree_node <value> * & root) {_ rb_tree_node <value> * Y = x-> right; X-> right = Y-> left; If (Y-> left! = 0) {Y-> left-> parent = x;} y-> parent = x-> parent; 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;} // global function 2-right-hand template <typename value> void _ rb_right_rotate (_ rb_tree_node <value> * X, _ rb_tree_node <value> * & root) {_ rb_tree_node <value> * Y = x-> left; X-> left = Y-> right; if (Y-> right! = 0) Y-> right-> parent = x; y-> parent = x-> parent; If (x = root) root = y; else if (x = x-> parent-> right) x-> parent-> right = y; else X-> parent-> left = y; y-> right = x; X-> parent = y;} // The third template of the global function <typename value> void _ rb_insert_fixup (_ rb_tree_node <value> * X, _ rb_tree_node <value> * & root) {While (X! = Root & X-> parent-> color = _ rb_tree_red) {If (X-> parent = x-> parent-> left) {_ rb_tree_node <value> * Y = x-> parent-> right; // If (Y & Y-> color = _ rb_tree_red) {// case1x-> parent-> color = _ rb_tree_black; y-> color = _ rb_tree_black; X-> parent-> color = _ rb_tree_red; X = x-> parent ;} else {If (x = x-> parent-> right) {// case2x = x-> parent; _ rb_left_rotate (x, root );} // case3x-> parent-> color = _ rb_tree_black; X-> parent-> color = _ rb_tree_red; _ rb_right_rotate (X-> parent, root) ;}} else {// symmetric case _ rb_tree_node <value> * Y = x-> parent-> left; if (Y & Y-> color = _ rb_tree_red) {// case1x-> parent-> color = _ rb_tree_black; y-> color = _ rb_tree_black; x-> parent-> color = _ rb_tree_red; X = x-> parent;} else {If (x = x-> parent-> left) {// case2x = x-> parent; _ rb_right_rotate (x, root);} // case3x-> parent-> color = _ rb_tree_black; x-> parent-> color = _ rb_tree_red; _ rb_left_rotate (X-> parent, root); }}root-> color = _ rb_tree_black ;}