Basic Properties of Red-Black Trees

Catalog

1. Basic Understanding of Red and Black Trees

(1) Understanding the basic definition of red and black trees

(2) Understanding that red-black trees are an approximate balance

1. Remove the red node from the red-black tree and analyze the height of the red-black tree containing the black node

2. Add the red node back and analyze the height change

(3) Comparison of red-black and AVL trees:

2. Analysis of the Basic Ideas of Realizing Red and Black Trees

(1) Understanding the rotate left and right operations

(2) Balance adjustment of insertion operation

Case 1: If the node of interest is a, its uncle node d is red

Situation 2: If the focus node is a, its uncle node d is black, and the focus node a is the right child of its parent node b

Case 3: If the focus node is a, its uncle node d is black, and the focus node a is the left child of its parent node b

The specific code above is as follows:

(3) Balance adjustment of deletion operation

1. Preliminary adjustments for deleting nodes

Scenario 1: If the node to be deleted is a, it has only one child node b

Scenario 2: If node a to be deleted has two non-empty child nodes and its successor node is the right child node c of node a

Scenario 3: If node a is to be deleted, it has two non-empty child nodes, and the successor node of node a is not a right child node

2. Secondary adjustment for nodes of interest

Scenario 1: If node of interest is a, its sibling node c is red

Scenario 2: If node of interest is a, its sibling node c is black, and the left and right child nodes d and e of node c are black

Case 3: If the node of interest is a, its sibling node c is black, its left child d is red, and its right child e is black

Situation 4: If the sibling node c of node a is black and the right child node of c is red

The specific code above is visible:

1. Basic Understanding of Red and Black Trees

(1) Understanding the basic definition of red and black trees

Red-Black Tree, or R-B Tree, is an unsecured balanced binary search tree.

Nodes in a red-black tree, one marked black and one marked red. In addition, a red-black tree needs to meet several requirements:

• The root node is black;
• Each leaf node is a black, empty node (NIL), which means that the leaf node does not store data (black, empty leaf nodes are omitted from the diagram);
• No adjacent node can be red at the same time, that is, the red node is separated by the black node;
• Each node, all paths from that node to its reachable leaf node, contains the same number of black nodes;

(2) Understanding that red-black trees are an approximate balance

The purpose of balancing binary lookup trees is to solve the performance degradation caused by dynamic updates of binary lookup trees. So the term "balance" can be equivalent to not degrading performance. Approximate Balance is equivalent to not degrading performance too severely.

A very balanced binary tree (full or complete) has a height of about log2n, so if you want to prove that the red-black tree is approximately balanced, you only need to analyze whether the height of the red-black tree approaches log2n more steadily.

1. Remove the red node from the red-black tree and analyze the height of the red-black tree containing the black node

When the red node is deleted, some nodes will have no parent, and they will take their grandparent node (the parent node of the parent node) directly as the parent node. So the previous binary tree becomes a quadtree.

When you take some nodes out of the quadtree and place them at the leaf node position, the quadtree becomes a complete binary tree. Therefore, the height of a quadtree containing only black nodes is smaller than that of a complete binary tree containing the same number of nodes.

The height of a complete binary tree is similar to log2n, where the height of a quadruple "black tree" is lower than that of a full binary tree, so the height of a "black tree" without a red node cannot exceed log2n.

2. Add the red node back and analyze the height change

In a red-black tree, a red node cannot be adjacent, that is, a red node must have at least one black node, separating it from other red nodes.

The path with the most black nodes in the red-black tree will not exceed log2n, so when the red node is added, the longest path will not exceed 2log2n, that is, the height of the red-black tree is approximately 2log2n.

Therefore, the height of the red-black tree is only twice as high as the height of the highly balanced AVL tree (log2n), and there is not much decline in performance. The results derived in this way are not accurate enough, in fact, the performance of red and black trees is better.

(3) Comparison of red-black and AVL trees:

• AVL trees are better than red and black trees in time complexity, but for today's computers, the cpu is too fast to ignore performance differences
• Insertion and deletion of red and black trees are easier to control than AVL trees
• The overall performance of red-black trees is slightly better than that of AVL trees (red-black trees rotate less than AVL trees).

2. Analysis of the Basic Ideas of Realizing Red and Black Trees

The balancing process of the red and black trees is very similar to the recovery of the Rubik's Cube. The general process is: what kind of node arrangement do we have to adjust. As long as these fixed adjustment rules are followed, an unbalanced red-black tree can be balanced.

As mentioned above, among the four basic requirements for a qualified red-black tree, the third and fourth requirements may be destroyed in the process of inserting and deleting nodes, while the "balance adjustment" is actually to restore the third and fourth points destroyed. Specific analysis is as follows:

(1) Understanding the rotate left and right operations

Left-handed means left-handed around a node. A, b and r in the graph represent subtrees and can be empty.

Code implementation:

```

/**

* Function description: balance is required on left-to-right side

*

* @author yanfengzhang

* @date 2020-05-27 14:57

*/

private
void
rotateLeft
(Entry<K, V> p) {

if (p !=
null) {

/*Get the right child of the root node */

Entry<K, V> r = p.right;

/*Assign a value to the left node of the right child of the root node*/

p.right = r.left;

if (r.left !=
null)

/*Assign the value of root node to the currently disconnected following node*/ {

r.left.parent = p;

}

/*r p.parent is the root of the new root node in the future, making it the new root node */

r.parent = p.parent;

if (p.parent ==
null) {

root = r;

}

/*If p is a left child, let him be a left child as well*/

else
if (p.parent.left == p) {

p.parent.left = r;

}
else {

p.parent.right = r;

}

/*The last converted value of the current exchange*/

r.left = p;

p.parent = r;

}

}

```

Right-handed means right-handed around a node. A, b and r in the graph represent subtrees and can be empty.

Code implementation:

```

/**

* Function description: Right hand code

*

* @author yanfengzhang

* @date 2020-05-27 14:58

*/

private
void
rotateRight
(Entry<K, V> p) {

if (p !=
null) {

Entry<K, V> l = p.left;

p.left = l.right;

if (l.right !=
null) {

l.right.parent = p;

}

l.parent = p.parent;

if (p.parent ==
null) {

root = l;

}
else
if (p.parent.right == p) {

p.parent.right = l;

}
else {

p.parent.left = l;

}

l.right = p;

p.parent = l;

}

}

```

(2) Balance adjustment of insertion operation

The red-black tree specifies that the inserted nodes must be red. Moreover, the newly inserted nodes in the binary search tree are placed on the leaf nodes.

There are two special cases of balance adjustment for insertion operations:

• If the parent node of the inserted node is black, we don't need to do anything, it still satisfies the red-black tree definition.
• If the inserted node is the root node, we can change its color directly and make it black.

In addition, other situations violate the definition of red and black trees and need to be adjusted, which involves two basic operations: left-right rotation and color change.

The balance adjustment process of red and black trees is an iterative process. Call the node being processed the node of interest. The nodes of interest change as they iterate over and over. The first node of interest is the newly inserted node. After inserting a new node, if the balance of the red and black trees is broken, there are generally three situations:

Note: We just need to keep adjusting according to the characteristics of each situation to keep the red and black trees in line with the definition, that is, to keep the balance. To simplify the description, the sibling node of the parent node is called the uncle node, and the parent node of the parent node is called the grandparent node.

Case 1: If the node of interest is a, its uncle node d is red

This is done by setting the color of the parent node b and uncle node d of node a to black. Set the color of the grandparent node c of node a to red; Focus on node becoming grandparent node c of a; Skip to scenario two or three.

Situation 2: If the focus node is a, its uncle node d is black, and the focus node a is the right child of its parent node b

The specific operations are as follows: the focus node becomes the parent node B of node a; Turn left around the new focus node b; Jump to scenario three.

Case 3: If the focus node is a, its uncle node d is black, and the focus node a is the left child of its parent node b

The specific operations are as follows: right-hand around the grandparent node c of node a; Change the color of parent node b and sibling node c of node a to end the adjustment.

The specific code above is as follows:

```

/**

* Function description: Insert a node

*

* @author yanfengzhang

* @date 2020-05-27 15:07

*/

private
void
insert
(RBTreeNode<T> node) {

int cmp;

RBTreeNode<T> root =
this.rootNode;

RBTreeNode<T> parent =
null;

/*Under which parent node the anchor node is added*/

while (
null != root) {

parent = root;

cmp = node.key.compareTo(root.key);

if (cmp <
0) {

root = root.left;

}
else {

root = root.right;

}

}

node.parent = parent;

/*Indicates that there is currently no node, then the new node is the root node*/

if (
null == parent) {

this.rootNode = node;

}
else {

//Find the location of the new node under the current parent node

cmp = node.key.compareTo(parent.key);

if (cmp <
0) {

parent.left = node;

}
else {

parent.right = node;

}

}

/*Set the color of the inserted node to red*/

node.color = COLOR_RED;

/*Fix to Black and Red Tree*/

insertFixUp(node);

}

/**

* Function Description: Red and Black Tree Insert Fix

*

* @author yanfengzhang

* @date 2020-05-27 15:07

*/

private
void
insertFixUp
(RBTreeNode<T> node) {

RBTreeNode<T> parent, gparent;

/*The parent node of the node exists and is red*/

while (((parent = getParent(node)) !=
null) && isRed(parent)) {

gparent = getParent(parent);

/*What if its grandparent node is empty, if it is the left child of the grandparent node*/

if (parent == gparent.left) {

RBTreeNode<T> uncle = gparent.right;

if ((
null != uncle) && isRed(uncle)) {

setColorBlack(uncle);

setColorBlack(parent);

setColorRed(gparent);

node = gparent;

continue;

}

if (parent.right == node) {

RBTreeNode<T> tmp;

leftRotate(parent);

tmp = parent;

parent = node;

node = tmp;

}

setColorBlack(parent);

setColorRed(gparent);

rightRotate(gparent);

}
else {

RBTreeNode<T> uncle = gparent.left;

if ((
null != uncle) && isRed(uncle)) {

setColorBlack(uncle);

setColorBlack(parent);

setColorRed(gparent);

node = gparent;

continue;

}

if (parent.left == node) {

RBTreeNode<T> tmp;

rightRotate(parent);

tmp = parent;

parent = node;

node = tmp;

}

setColorBlack(parent);

setColorRed(gparent);

leftRotate(gparent);

}

}

setColorBlack(
this.rootNode);

}

```

(3) Balance adjustment of deletion operation

The balancing adjustment of the delete operation is divided into two steps:

The first step is to make initial adjustments to delete nodes. The preliminary adjustment only guarantees that the whole red-black tree will meet the last defined requirement after one node is deleted, that is, every node, all paths from that node to its reachable leaf nodes, contains the same number of black nodes;

The second step is to make a secondary adjustment to the node of interest so that it satisfies the third definition of the red-black tree, that is, there are no two adjacent red nodes.

1. Preliminary adjustments for deleting nodes

The definition of red-black tree contains only red and black nodes. After preliminary adjustment, some nodes will be marked in two colors, red-black or black-black, in order to meet the last requirements of the definition of red-black tree. If a node is marked as black-black, it is counted as two black nodes when counting the number of black nodes.

Note: If a node can be either red or black, the figure is represented by half red and half black. If a node is red-black or black-black, the extra black is represented by a small black dot in the upper left corner.

Scenario 1: If the node to be deleted is a, it has only one child node b

The specific operations are as follows: delete node A and replace node b with the position of node a, which is the same as the normal deletion of a binary search tree; Node a can only be black, node b can only be red, otherwise it does not fit the definition of red-black tree. In this case, we change node b to black; Adjustment is complete, no secondary adjustment is required.

Scenario 2: If node a to be deleted has two non-empty child nodes and its successor node is the right child node c of node a

This is done as follows: if the successor node of node a is the right child node c, then the right child node C must not have a left subtree. We delete node A and replace node C with the location of node a. This part of the operation is the same as deleting a binary search tree. Then set the color of node C to be the same as that of node a. If node C is black, in order not to violate the last definition of the red-black tree, we add an extra black to the right child node D of node c, at which time node D becomes either "red-black" or "black-black"; At this point, the focus node becomes node d, and the second step of adjustment will be for the focus node.

Scenario 3: If node a is to be deleted, it has two non-empty child nodes, and the successor node of node a is not a right child node

The specific operations are as follows: find the succeeding node d, delete it, delete the succeeding node D process refers to CASE 1; Replace node a with successor node d; Set the color of node d to be the same as that of node a; If node D is black, in order not to violate the last definition of the red-black tree, we add a black to the right child node C of node d, at which time node C becomes either "red-black" or "black-black"; At this point, the focus node becomes node c, and the second step of adjustment will be for the focus node.

2. Secondary adjustment for nodes of interest

After the initial adjustment, the focus node becomes a red-black or BLACK-BLACK node. For this node of interest, there are four cases to make secondary adjustments.

Note: The secondary adjustment is to make no adjacent red nodes in the red-black tree.

Scenario 1: If node of interest is a, its sibling node c is red

Actions: Rotate left around the parent node b of node a; Note that node a's parent node b and grandparent node c exchange colors; The focus node is unchanged; Continue to select the appropriate rule from the four cases to adjust.

Scenario 2: If node of interest is a, its sibling node c is black, and the left and right child nodes d and e of node c are black

Specific operations: turn the color of the sibling node c concerned with node a to red; Remove a black from node a of interest, where node a is pure red or black; Add a black to the parent node B of node a, at which point node B becomes either "red-black" or "black-black"; Focus on the node changing from a to its parent b; Continue to adjust by choosing the rule that meets from four scenarios.

Case 3: If the node of interest is a, its sibling node c is black, its left child d is red, and its right child e is black

Specific operations: turn right around the sibling node c of node a; Node c and node d exchange colors; The focus node is unchanged; Jump to CASE 4 and continue adjusting.

Situation 4: If the sibling node c of node a is black and the right child node of c is red

Actions: Rotate left around the parent node b of node a; Set the color of the sibling node c of node a to be the same as that of the parent node b of node a. Set the color of the parent node b of node a to black; By removing a black from node a of interest, node a becomes pure red or black; Set uncle node e of node a to black; End of adjustment.

The specific code above is visible:

```

/**

* Function description: Delete node

*

* @author yanfengzhang

* @date 2020-05-27 15:11

*/

private
void
remove
(RBTreeNode<T> node) {

RBTreeNode<T> child, parent;

boolean color;

/*Removed node left and right children are not empty*/

if ((
null != node.left) && (
null != node.right)) {

/*Get the succeeding node of the deleted node*/

RBTreeNode<T> replace = node;

replace = replace.right;

while (
null != replace.left) {

replace = replace.left;

}

/*node Node is not root*/

if (
null != getParent(node)) {

/*node Is left node*/

if (getParent(node).left == node) {

getParent(node).left = replace;

}
else {

getParent(node).right = replace;

}

}
else {

this.rootNode = replace;

}

child = replace.right;

parent = getParent(replace);

color = getColor(replace);

if (parent == node) {

parent = replace;

}
else {

if (
null != child) {

setParent(child, parent);

}

parent.left = child;

replace.right = node.right;

setParent(node.right, replace);

}

replace.parent = node.parent;

replace.color = node.color;

replace.left = node.left;

node.left.parent = replace;

if (color == COLOR_BLACK) {

removeFixUp(child, parent);

}

node =
null;

return;

}

if (
null != node.left) {

child = node.left;

}
else {

child = node.right;

}

parent = node.parent;

color = node.color;

if (
null != child) {

child.parent = parent;

}

if (
null != parent) {

if (parent.left == node) {

parent.left = child;

}
else {

parent.right = child;

}

}
else {

this.rootNode = child;

}

if (color == COLOR_BLACK) {

removeFixUp(child, parent);

}

node =
null;

}

/**

* Function Description: Delete Repair

*

* @author yanfengzhang

* @date 2020-05-27 15:11

*/

private
void
removeFixUp
(RBTreeNode<T> node, RBTreeNode<T> parent) {

RBTreeNode<T> other;

/*node Not empty and black, and not root node*/

while ((
null == node || isBlack(node)) && (node !=
this.rootNode)) {

/*node Is the left child of the parent node*/

if (node == parent.left) {

/*Get their right child*/

other = parent.right;

/*node The sibling node of the node is red*/

if (isRed(other)) {

setColorBlack(other);

setColorRed(parent);

leftRotate(parent);

other = parent.right;

}

/*node The sibling node of the node is black, and the two child nodes of the sibling node are also black*/

if ((other.left ==
null || isBlack(other.left)) &&

(other.right ==
null || isBlack(other.right))) {

setColorRed(other);

node = parent;

parent = getParent(node);

}
else {

/*node The sibling node of the node is black, and the right child of the sibling node is red*/

if (
null == other.right || isBlack(other.right)) {

setColorBlack(other.left);

setColorRed(other);

rightRotate(other);

other = parent.right;

}

/*node The sibling node of the node is black, and the right child of the sibling node is red, and the left child is any color*/

setColor(other, getColor(parent));

setColorBlack(parent);

setColorBlack(other.right);

leftRotate(parent);

node =
this.rootNode;

break;

}

}
else {

other = parent.left;

if (isRed(other)) {

setColorBlack(other);

setColorRed(parent);

rightRotate(parent);

other = parent.left;

}

if ((
null == other.left || isBlack(other.left)) &&

(
null == other.right || isBlack(other.right))) {

setColorRed(other);

node = parent;

parent = getParent(node);

}
else {

if (
null == other.left || isBlack(other.left)) {

setColorBlack(other.right);

setColorRed(other);

leftRotate(other);

other = parent.left;

}

setColor(other, getColor(parent));

setColorBlack(parent);

setColorBlack(other.left);

rightRotate(parent);

node =
this.rootNode;

break;

}

}

}

if (node !=
null) {

setColorBlack(node);

}

}

```

2. The Beauty of Data Structure and Algorithms, Wang Zheng (Former Google Engineer), Geek Time, 2019

Tags: data structure

Posted on Sun, 05 Dec 2021 16:19:23 -0500 by larissahn