Deep understanding of red black tree addition and deletion nodes

Keywords: data structure

Purpose:

It is mainly used in key value search

  1. map
  2. nginx Timer event management
  3. Epoll event block management
  4. cfs
  5. memory management
    Like malloc
    Sketch Map

Red black tree characteristics:

1, Each node is red or black
2, The root node is black
3, Each leaf node is black and hidden
4, If a node is red, its child nodes are black
5, For a node, all paths from the node to its descendants contain the same number of black nodes (balanced black height of red black tree)
6, The maximum path will not exceed twice the shortest path (because red must be followed by black, and the number of black nodes must be equal).

realization

Red black tree time complexity: O(lgn)

Red black tree application:
It is mainly used to store data, such as TreeSet and TreeMap in Java collection, set and map in C + +, and virtual memory management in linux

Red black tree - left-handed


So it is said in the introduction to algorithm

LEFT-ROTATE(T, x)  
	y ← right[x]            // Premise: let's assume that the right child of x is y. Let's start the formal operation
	right[x] ← left[y]      // Set "y's left child" to "x's right child", about to β Right child set to x
	p[left[y]] ← x          // Set "x" to "y's left child's father", about to β The father of is set to x
	p[y] ← p[x]             // Set "father of x" to "father of y"
	if p[x] = nil[T]       
		then root[T] ← y                 // Case 1: if "x's father" is an empty node, set y as the root node
	else if x = left[p[x]]  
		then left[p[x]] ← y    // Case 2: if x is the left child of its parent node, set y as "the left child of X's parent node"
	else 
		right[p[x]] ← y   // Case 3: (x is the right child of its parent node) set y as "the right child of X's parent node"
	left[y] ← x             // Set "x" to "y's left child"
	p[x] ← y                // Set "parent of x" to "y"
void _left_route(rbtree *T, rbtree_node * x)
{
	rbtree_node *y = x->right;
 	
 	x->right = y->left;
 	if(y->left != T->nil)
 		y->left->parent = x;

	if(x->parent != T->nil)
	{
		y->parent = T->root;
	}
	else if(x == x->parent->left)
	{
		x->parent->left = y;
	}
	else if(x == x->parent->right)
	{
		x->parent->right = y;
	}
	y->parent = x->parent;

	x->parent = y;
	y->left = x;
}

Red black tree - right rotation


It is said in the introduction to algorithm:

RIGHT-ROTATE(T, y)  
 	x ← left[y]             // Premise: let's assume that the left child of y is x. Let's start the formal operation
 	left[y] ← right[x]      // Set "x's right child" to "Y's left child", about to β Left child set to y
	p[right[x]] ← y         // Set "Y" to "the father of the right child of x", about to β My father is set to y
	p[x] ← p[y]             // Set "father of y" to "father of x"
	if p[y] = nil[T]       
		then root[T] ← x                 // Case 1: if "y's father" is an empty node, set x as the root node
	else if y = right[p[y]]  
		then right[p[y]] ← x   // Case 2: if y is the right child of its parent node, set x as "the left child of Y's parent node"
	else 
		left[p[y]] ← x    // Case 3: (y is the left child of its parent node) set x as "the left child of Y's parent node"
	right[x] ← y            // Set "y" to "right child of x"
	p[y] ← x                // Set "parent node of y" to "x"
void _right_route(rbtree *T, rbtree_node * x)
{
	rbtree_node *y = x->left;
 	
 	x->left= y->right;
 	if(y->right!= T->nil)
 		y->right->parent = x;

	if(x->parent != T->nil)
	{
		y->parent = T->root;
	}
	else if(x == x->parent->left)
	{
		x->parent->left = y;
	}
	else if(x == x->parent->right)
	{
		x->parent->right = y;
	}
	y->parent = x->parent;

	x->parent = y;
	y->right= x;
}

The red black tree is a binary tree, and the binary tree must meet the sorting requirements. Therefore, the left and right rotation of the red black tree only changes the parent-child node relationship of X and Y nodes

Red black tree addition

Red black trees can be added in the following ways:

The red part of the parent node in the above figure can be summarized into three cases,

  1. The parent node is red and the uncle node is red
    Processing method: transform the parent node and uncle node to black and the grandfather node to red. Then process the grandfather node to meet the red black tree value: the child node of the red node cannot be red!
  2. The parent node is red and the uncle node is black. The parent node and the current node are on the same side of the tree, either the left subtree of the parent node or the right subtree of the parent node
    Processing method: rotate the grandfather node so that the parent node is in the position of the previous grandfather node, exchange the colors of the parent node and the grandfather node, so that the original grandfather node is still in black and its two child nodes become red
  3. The parent node is red, the uncle node is black, and the parent node is in a different state from the current node.
    Processing method: transform two consecutive red to the same side as the parent node by rotation, and then process according to the second case.
void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {

	while (z->parent->color == RED) { //z ---> RED
		if (z->parent == z->parent->parent->left) {
			rbtree_node *y = z->parent->parent->right;
			if (y->color == RED) {
				z->parent->color = BLACK;
				y->color = BLACK;
				z->parent->parent->color = RED;

				z = z->parent->parent; //z --> RED
			} else {

//Make sure that the current node and the parent node are on the same side of the tree. If not, rotate and transform a red node to the same side, and then hand over the node handle.
//The core of the transformation here is to pull one of the two consecutive red nodes to the position of the grandfather node through rotation, and then color. In this way, the black height will not be changed to achieve balance
				if (z == z->parent->right) {
					z = z->parent;
					_left_rotate(T, z);
				}

				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				_right_rotate(T, z->parent->parent);
			}
		}else {
			rbtree_node *y = z->parent->parent->left;
			if (y->color == RED) {
				z->parent->color = BLACK;
				y->color = BLACK;
				z->parent->parent->color = RED;

				z = z->parent->parent; //z --> RED
			} else {
				if (z == z->parent->left) {
					z = z->parent;
					_right_rotate(T, z);
				}

				z->parent->color = BLACK;
				z->parent->parent->color = RED;
				_left_rotate(T, z->parent->parent);
			}
		}
		
	}

	T->root->color = BLACK;
}
void rbtree_insert(rbtree *T, rbtree_node *z) {

	rbtree_node *y = T->nil;
	rbtree_node *x = T->root;
//Find the location where the z node should be added, and refer to the binary tree property value
	while (x != T->nil) {
		y = x;
		if (z->key < x->key) {
			x = x->left;
		} else if (z->key > x->key) {
			x = x->right;
		} else { //Exist
			return ;
		}
	}

	z->parent = y;
	if (y == T->nil) {
		T->root = z;
	} else if (z->key < y->key) {
		y->left = z;
	} else {
		y->right = z;
	}

	z->left = T->nil;
	z->right = T->nil;
	//Red
	z->color = RED;
//Modify the color to meet the red black tree property value
	rbtree_insert_fixup(T, z);
}

Delete node

Three node definitions

  1. Overwrite node z: the node corresponding to the key you want to delete
  2. Delete node y: the minimum value of the actually released node at the right node of z. if z is missing the left and right subtrees, it overlaps with x
  3. The child node of the pivot node x: y, from which the red and black attributes are adjusted

To delete a node

  1. Find x, y nodes
  2. Disconnect the Y node and graft the x node to the original y node.
  3. Copy the contents of the y node to the z node
  4. If the deleted node y is a black node, adjust the red and black so that the tree still meets the red and black tree attribute
rbtree_node *rbtree_delete(rbtree *T, rbtree_node *z) {

	rbtree_node *y = T->nil;
	rbtree_node *x = T->nil;
// Find x, y nodes
	if ((z->left == T->nil) || (z->right == T->nil)) {
		y = z;
	} else {
		y = z->right;
		while(y->left != T->nil)
		{
			y = y->left;
		}
	}

	if (y->left != T->nil) {
		x = y->left;
	} else if (y->right != T->nil) {
		x = y->right;
	}
// Delete y node
	x->parent = y->parent;
	if (y->parent == T->nil) {
		T->root = x;
	} else if (y == y->parent->left) {
		y->parent->left = x;
	} else {
		y->parent->right = x;
	}

	if (y != z) {
		z->key = y->key;
		z->value = y->value;
	}

	if (y->color == BLACK) {
		rbtree_delete_fixup(T, x);
	}
	free(y);
	
}

Adjust red black tree attributes

There may be a situation when adjusting the tree. x is red. Since neither parent nor child nodes in red can be red, it is good to dye black directly, which is not discussed here.



void rbtree_delete_fixup(rbtree *T, rbtree_node *x) {

	while ((x != T->root) && (x->color == BLACK)) {
		if (x == x->parent->left) {![Insert picture description here](https://img-blog.csdnimg.cn/6196174218ec42b99bed6e099cc48369.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAcXFfNTAzMDAwODk1,size_20,color_FFFFFF,t_70,g_se,x_16)


			rbtree_node *w= x->parent->right;
			if (w->color == RED) {
				w->color = BLACK;
				x->parent->color = RED;

				_left_rotate(T, x->parent);
				w = x->parent->right;
			}

			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				w->color = RED;
				x = x->parent;
			} else {

				if (w->right->color == BLACK) {
					w->left->color = BLACK;
					w->color = RED;
					_right_rotate(T, w);
					w = x->parent->right;
				}

				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->right->color = BLACK;
				_left_rotate(T, x->parent);

				x = T->root;
			}

		} else {

			rbtree_node *w = x->parent->left;
			if (w->color == RED) {
				w->color = BLACK;
				x->parent->color = RED;
				_right_rotate(T, x->parent);
				w = x->parent->left;
			}

			if ((w->left->color == BLACK) && (w->right->color == BLACK)) {
				w->color = RED;
				x = x->parent;
			} else {

				if (w->left->color == BLACK) {
					w->right->color = BLACK;
					w->color = RED;
					_left_rotate(T, w);
					w = x->parent->left;
				}

				w->color = x->parent->color;
				x->parent->color = BLACK;
				w->left->color = BLACK;
				_right_rotate(T, x->parent);

				x = T->root;
			}

		}
	}

	x->color = BLACK;
}

Posted by prc on Fri, 22 Oct 2021 22:40:48 -0700