Red/black tree in nginx and nginx
Okay, nginx is a fake. This section mainly introduces some theoretical knowledge about the red and black trees. The main source code of nginx is attached to it. This article does not cover all aspects, and my level is not that high.
Features of the red/black tree:
1. The red/black tree is a binary search tree.
2. Each node on the tree is red or black.
3. If a node is red, its left and right child nodes must be black.
4. The black knots from the root node to each leaf node path are the same.
5. The root node must be black.
It is important to understand these features. These features ensure the efficiency of the red and black trees. (As for why, I am still not refined, so I will not talk about it in disorder .).
The insert and delete node actions of the red/black tree follow the Binary Search Tree rules. However, after basic operations are completed, if a feature of the red/black tree is violated, some rotation operations are required to balance the red/Black nodes. Therefore, a considerable part of the insert and Delete actions are the basic Binary Search Tree insertion and deletion. This article only lists the situations that require rotation.
Insert operation of the red/black tree:
The conventions are as follows: the current operation node is X, the parent node of X is P, the parent node of P is PP, And the sibling node of P is S.
According to rule 4, the newly inserted node (X) must be red. If the parent node (P) of X is also red. If rule 3 is violated, the rotation operation must be performed to meet the characteristics. There are three cases.
I1:
X is red, P is red, and S is black. You can export PP or black.
Step 3: Set P to black, set PP to red, and PP to right. (The opposite is true ).
I2:
X is red, P is red, and S is black. You can export PP or black.
Directly rotate P to the left, which is changed to i1. Follow the I1 step for balancing (the opposite is true, and the opposite is true ).
I3:
X is red, P is red, and S is red. You can export PP to black.
In this case, set P and S to black and set PP to red. This is a special case. What if the PPP of the PP parent node is red? Then, the P node is the new X and recursive upwards. Until PPP is black. If recursion is performed on the root node, set root to black. (Equivalent to the number of black nodes in each path plus 1 at the same time ).
So far, the insert theory of the red and black trees has been fully explained. Have you made it clear?
Delete a red/black tree:
The first step of deleting the red/black tree also follows the law of the Binary Search Tree.
Assume that the node to be deleted is Y. There are three scenarios:
At this point, the node deletion has been completed. The second step is to balance the red and black nodes, which meet the requirements of the red and black trees.
The conventions are as follows: the current operation node is X, the parent node of X is P, and the brother node of X is S (note that this is the brother of X ). The child node of S is Sl Sr.
D1:
X is black, and S is red. Then the Sl Sr must be black.
After the transformation, the tree does not satisfy the property of the Red-black tree, but instead converts it to another situation. (D2 D3 D4 ).
D2:
X is black, and S is black. The Sl Sr is black.
Because X is deleted, the X branch has one less black node than the S branch. After S is set to red, the black node of the left and right branches of the subtree is balanced (one less than that of other branches ). Therefore, Set P to the new X. (It is easy to understand and do not draw a picture here ).
D3:
X is black, and S is black. The Sl value is red Sr-bit black.
S sets red Sl to black. S right rotation. Convert to D4.
D4:
X is black, and S is black. Then, Sl is black Sr red.
Set S to the color of P and P to the black color. Set Sr to black. Rotate P on the left. Then the black node missing from the left subtree is supplemented. Deleted successfully.
It can be seen that when the deleted node has left and right subtree, only D4 can truly achieve the balance. D1 D2 D3 is converted to D4.
When talking about it, I feel ugly. If you have written all the data, send it out.
Why is the theory above so simple and crude? That's exactly what nginx writes.
Insert code:
Voidngx_rbtree_insert (ngx_rbtree_t * tree, ngx_rbtree_node_t * node) {ngx_rbtree_node_t ** root, * temp, * sentinel;/* a binary tree insert */root = (optional **) & tree-> root; sentinel = tree-> sentinel; // sentinel is the sentinel. I think it is NULL if (* root = sentinel) {node-> parent = NULL; node-> left = sentinel; node-> right = sentinel; ngx_rbt_black (node); * root = node; return;} tree-> insert (* root, node, sent Inel); // insert a node based on the binary search tree/* re-balance tree */while (node! = * Root & ngx_rbt_is_red (node-> parent) {// balance the red and black nodes if (node-> parent = node-> parent-> left) {temp = node-> parent-> right; if (ngx_rbt_is_red (temp) {// I3 ngx_rbt_black (node-> parent); ngx_rbt_black (temp ); ngx_rbt_red (node-> parent); node = node-> parent;} else {if (node = node-> parent-> right) {// I2 node = node-> parent; ngx_rbtree_left_rotate (root, sentinel, node );} Ngx_rbt_black (node-> parent); // I1 ngx_rbt_red (node-> parent); ngx_rbtree_right_rotate (root, sentinel, node-> parent );}} else {// the opposite direction is the same. Temp = node-> parent-> left; if (ngx_rbt_is_red (temp) {ngx_rbt_black (node-> parent); ngx_rbt_black (temp ); ngx_rbt_red (node-> parent); node = node-> parent;} else {if (node = node-> parent-> left) {node = node-> parent; ngx_rbtree_right_rotate (root, sentinel, node);} ngx_rbt_black (node-> parent); ngx_rbt_red (node-> parent ); ngx_rbtree_left_rotate (root, sentinel, node-> p Arent-> parent) ;}}} ngx_rbt_black (* root); // brainless settings, in any situation .}
Delete Code:
Voidngx_rbtree_delete (ngx_rbtree_t * tree, ngx_rbtree_node_t * node) {ngx_uint_t red; ngx_rbtree_node_t ** root, * sentinel, * subst, * temp, * w; /* a binary tree delete */root = (ngx_rbtree_node_t **) & tree-> root; sentinel = tree-> sentinel; // sentinel (NULL) if (node-> left = sentinel) {// scenario 1 delete node Y as a single node or leaf node temp = node-> right; subst = node ;} else if (node-> right = sentinel) {// case 1 delete node Y as single node or leaf node tem P = node-> left; subst = node;} else {// case 1 3 delete node Y as the double-Supporting node subst = ngx_rbtree_min (node-> right, sentinel ); if (subst-> left! = Sentinel) {temp = subst-> left;} else {temp = subst-> right;} if (subst = * root) {* root = temp; ngx_rbt_black (temp);/* DEBUG stuff */node-> left = NULL; node-> right = NULL; node-> parent = NULL; node-> key = 0; return;} red = ngx_rbt_is_red (subst); // record the color of Y if (subst = subst-> parent-> left) {// here it is based on the nature of the Binary Search Tree, delete the node and generate a new binary search tree. Subst-> parent-> left = temp;} else {subst-> parent-> right = temp;} if (subst = node) {temp-> parent = subst-> parent;} else {if (subst-> parent = node) {temp-> parent = subst ;} else {temp-> parent = subst-> parent;} subst-> left = node-> left; subst-> right = node-> right; subst-> parent = node-> parent; ngx_rbt_copy_color (subst, node); if (node = * root) {* root = subst ;} else {if (node = node-> Parent-> left) {node-> parent-> left = subst;} else {node-> parent-> right = subst ;}} if (subst-> left! = Sentinel) {subst-> left-> parent = subst;} if (subst-> right! = Sentinel) {subst-> right-> parent = subst;}/* DEBUG stuff */node-> left = NULL; node-> right = NULL; node-> parent = NULL; node-> key = 0; if (red) {// delete node Y is red and exit return directly ;} /* a delete fixup */while (temp! = * Root & ngx_rbt_is_black (temp) {// temp is the X above. Start to balance the red and black nodes. Until X is red, or if (temp = temp-> parent-> left) {w = temp-> parent-> right; if (ngx_rbt_is_red (w )) {// D1 ngx_rbt_black (w); ngx_rbt_red (temp-> parent); ngx_rbtree_left_rotate (root, sentinel, temp-> parent); w = temp-> parent-> right ;} if (ngx_rbt_is_black (w-> left) & ngx_rbt_is_black (w-> right) {// D2 ngx_rbt_red (w); temp = temp-> parent ;} else {if (ngx_rbt_is_black (w-> right) {// D3 ngx_rbt_black (w-> l Eft); ngx_rbt_red (w); ngx_rbtree_right_rotate (root, sentinel, w); w = temp-> parent-> right;} ngx_rbt_copy_color (w, temp-> parent ); // D4 ngx_rbt_black (temp-> parent); ngx_rbt_black (w-> right); ngx_rbtree_left_rotate (root, sentinel, temp-> parent); temp = * root ;}} else {// the opposite direction is the same. W = temp-> parent-> left; if (ngx_rbt_is_red (w) {ngx_rbt_black (w); ngx_rbt_red (temp-> parent); ngx_rbtree_right_rotate (root, sentinel, temp-> parent); w = temp-> parent-> left;} if (ngx_rbt_is_black (w-> left) & ngx_rbt_is_black (w-> right )) {ngx_rbt_red (w); temp = temp-> parent;} else {if (ngx_rbt_is_black (w-> left) {ngx_rbt_black (w-> right); ngx_rbt_red (w ); ngx_rbtree_left_rotate (root, sentinel, w); w = temp-> parent-> left;} ngx_rbt_copy_color (w, temp-> parent); ngx_rbt_black (temp-> parent ); ngx_rbt_black (w-> left); ngx_rbtree_right_rotate (root, sentinel, temp-> parent); temp = * root; }}} ngx_rbt_black (temp); // set black}
What I wrote here is actually shit. Let's take a look at nginx source code. The Study on the red and black trees completely rewrites the volume soil. Click it.