Preface
Understanding the red-black tree requires the following knowledge
- Binary search algorithm
- Binary search tree
- Self-balancing tree (AVL tree and red-black tree)
A binary search tree was designed based on a binary search tree. In order to compensate for the skew of the binary search tree, some self-balancing trees, such as AVL trees, red-black trees, etc., appeared.
Binary search algorithm
It only takes 32 times to find a specified data in 4 billion data, which is the charm of binary search algorithm.
binary search algorithm (also known as binary search algorithm ) is a kind of ordered array find a particular element of search algorithm . Note the premise of the ordered array
Look at Figure 4, to find the middle element from the beginning 4 < 7
look from the left 4 > 3
look from the right 4 < 6
, then find the elements.
Binary search algorithm time and space complexity, \( {n} \) is the length of the array.
Average time complexity\( {O(\log n)} \)
Worst time complexity\( {O(\log n)} \)
Optimal time complexity\( {O(1)} \)
Cyclic space complexity\( {O(1)} \)
Recursive space complexity\( {O(\log n)} \)
Java recursively implements binary search.
public static int binarySearch(int[] arr, int start, int end, int hkey) {
if (start > end) {
return -1;
}
int mid = start + (end - start) / 2; //防止溢位
if (arr[mid] > hkey) {
return binarySearch(arr, start, mid - 1, hkey);
}
if (arr[mid] < hkey) {
return binarySearch(arr, mid + 1, end, hkey);
}
return mid;
}
Java loop implements binary search.
public static int binarySearch(int[] arr, int start, int end, int hkey) {
int result = -1;
while (start <= end) {
int mid = start + (end - start) / 2; //防止溢位
if (arr[mid] > hkey) {
end = mid - 1;
} else if (arr[mid] < hkey) {
start = mid + 1;
} else {
result = mid;
break;
}
}
return result;
}
Binary search tree
Binary Search Tree (Binary Search Tree, BST for short) is a binary tree with the following properties:
- If the left subtree of any node is not empty, the values of all nodes on the left subtree are less than the value of its root node;
- If the right subtree of any node is not empty, the values of all nodes on the right subtree are greater than the value of its root node;
- The left and right subtrees of any node are also binary search trees.
Binary tree: Each node has at most two branches, which are called "left subtree" or "right subtree" respectively.
The efficiency of binary search tree operations (search, insert, delete) depends on the height of the tree.
In the worst case, the tree is inclined to one side, and the tree height is $n$ (the number of nodes). At this time, the operation time complexity is $O(n)$
Ideally, the tree height is $log(n)$ and the operation time complexity is $O(log(n))$. At this time, it is a binary search tree with balanced by
algorithm | average | Worst |
---|---|---|
space | O(n) | O(n) |
search | O(log n) | O(n) |
insert | O(log n) | O(n) |
delete | O(log n) | O(n) |
In order to make the binary search tree reach the ideal situation as much as possible, some self-balancing binary search trees have appeared, such as AVL tree and red-black tree .
AVL tree
Each node in the AVL tree has a balance factor attribute (the height of the left subtree minus the height of the right subtree). After each element insertion and deletion operations, calculations will be carried out again, if the balance factor is not the node [0, -1], need rotation that the tree reaches equilibrium. There are 4 rotation operations in the AVL tree.
- Left Rotation
- RightRotation
- Left-Right Rotation
- Right-Left Rotation
Below is an example of a Java AVL tree
private Node insert(Node node, int key) {
.....
return rebalance(node); // 重新平衡计算
}
private Node delete(Node node, int key) {
.....
node = rebalance(node); // 重新平衡计算
return node;
}
private Node rebalance(Node z) {
updateHeight(z);
int balance = getBalance(z);
if (balance > 1) {
if (height(z.right.right) > height(z.right.left)) {
z = rotateLeft(z);
} else {
z.right = rotateRight(z.right);
z = rotateLeft(z);
}
} else if (balance < -1) {
if (height(z.left.left) > height(z.left.right)) {
z = rotateRight(z);
} else {
z.left = rotateLeft(z.left);
z = rotateRight(z);
}
}
return z;
}
https://github.com/eugenp/tutorials/blob/master/data-structures/src/main/java/com/baeldung/avltree/AVLTree.java
Red black tree
nature
Each node in the red-black tree has a color attribute. After each element insertion deletion, it will be re- coloring and rotation balance.
The red-black tree belongs to the binary search tree, which contains the properties of the binary search tree, and also contains the following properties:
- Each node is either black or red.
- All leaf nodes (NIL) are considered black.
- The two child nodes of each red node must be black (two consecutive red nodes will not appear).
- Each path from the root to the leaf node (NIL) contains the same number of black nodes.
Find
The search will not destroy the balance of the tree, and the logic is relatively simple. There are usually the following steps.
- Search from the root node and set the root node as the current node;
- If the current node is empty, return null;
- The current node is not empty, the search key is smaller than the current node key, and the left child node is set as the current node.
- The current node is not empty, the search key is greater than the current node key, and the right child node is set as the current node.
- The current node is not empty, and the search key is equal to the current node key, and the current node is returned.
Code implementation can refer to TreeMap in Java.
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0){
p = p.left;
}else if (cmp > 0){
p = p.right;
}else{
return p;
}
}
return null;
insert
The insertion operation is divided into two parts: one is to find the insertion position; the other is to self-balance after insertion.
- Assign the root node to current node , and find the inserted node in a loop;
- When the search key is equal to current node key, update the value stored in the node, and return;
- When the search key is less than the current node key, set the left child node of the current node as the current node;
- When the search key is greater than current node key, set the right child node of the current node as the current node;
- After the cycle, the new node is configured as current node left (right) child node;
- Self-balance by rotating to change color.
Code implementation can refer to TreeMap in Java.
Entry<K,V> t = root;
Entry<K,V> parent;
int cmp;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0){
t = t.left;
}else if (cmp > 0){
t = t.right;
}else {
return t.setValue(value); // 更新节点的值,返回
}
} while (t != null);
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0){
parent.left = e;
}else {
parent.right = e;
}
fixAfterInsertion(e); // 通过旋转变色自平衡
Insert scene analysis
- If the root node is empty, set the inserted node as the root node and set it to black;
- The key of the inserted node already exists, only the inserted value needs to be updated, and there is no need to self-balance;
- The parent node of the inserted node is black, and it is inserted directly without self-balancing;
- The parent node of the inserted node is red.
Scenario 4 After inserting the node, there two consecutive red nodes , 1619bb78943527, so is required to recolor and rotate . There are many situations in this, see below for details.
First declare the next node relationship, ancestor node (10), uncle node (20), parent node (9), insert node (8).
Generally, the appropriate balance operation is determined by judging the uncle of the inserted node.
uncle node exists and is red .
- First find the location and insert the node 8 ;
- parent node 9 and uncle node 20 to black, grandfather node 10 to red;
- ancestor node 10 is the root node, so it turns black again.
uncle node does not exist or is black, the parent node is the left node of the ancestor node, and the inserted node is the left child node of the parent node.
- First find the location and insert node 7 ;
- ancestor node 9 to the right;
- parent node 8 to black, and grandfather node 9 to red;
uncle node does not exist or is black, the parent node is the left node of the ancestor node, and the inserted node is the right child node of the parent node.
- First find the location and insert node 8 ;
- parent node 7 to the left;
- ancestor node 9 to the right;
- Insert node 8 into black, ancestor node 9 into red;
uncle node does not exist or is black, the parent node is the right node of the ancestor node, and the inserted node is the right child node of the parent node.
- First find the location and insert node 10 ;
- ancestor node 8 to the left;
- parent node 9 to black, and grandfather node 8 to red;
uncle node does not exist or is black, the parent node is the right node of the ancestor node, and the inserted node is the left child node of the parent node.
- First find the location and insert the node 9 ;
- parent node 10 to the right;
- ancestor node 8 to the left;
- Insert node 9 into black, and grandfather node 8 into red;
delete
The delete operation is divided into two parts: one is to find the node to delete; the other is to self-balance after the deletion. After deleting the node, you need to find the node to replace the deleted location.
The properties after the binary search tree, to delete a node, can maximum left subtree or the right subtree minimum to replace the deleted node. If the deleted node has no child nodes, you can delete it directly without replacing it; if there is only one child node, replace it with this child node.
Consider some deletion scenarios and use the following visualization tools to simulate the scenario.
https://www.cs.csubak.edu/~msarr/visualizations/RedBlack.html
Replace the node and delete one of the nodes red
- Find delete node 3 , delete it;
- node 2 replaces the deletion position, and becomes the black of delete node 3
replacement node and the deleted node are both black, its sibling node is black, and at least one child node of the sibling node is red.
replacement node and the deleted node are both black, its sibling node is black, and at least one child node of the sibling node is red.
replacement node and the deleted node are both black, its sibling node is black, and the two child nodes of the sibling node are black.
replacement node and the deleted node are both black, and its sibling node is red .
AVL tree and red-black tree comparison
The following are pictures of [1-10] stored in AVL tree and red-black tree As can be seen:
- AVL tree more strictly balanced, which brings faster query speed. In order to maintain a strict balance, the performance cost of frequent rotations needs to be paid.
- red-black tree than the demanding AVL tree.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。