The red-black tree data structure - movable FIG Demo (lower)

Insert and delete nodes

We know that in order to correct color and rotation are damaged red-black tree, so that the rules in line with the red-black tree, the new equilibrium. Then add or remove nodes how to operate in a particular situation?

Insert Node

Node into red-black tree with a binary search tree insertion procedure is the same, only the last step in a multi- balance adjustment operation.

The newly inserted node defaults to the red nodes, there is no need for balance adjustment, only need to be adjusted when inserted into the red next node when a new node is inserted into the black node, due to a violation under the red node is inserted into two adjacent red nodes can not rule.

Balance adjustment of the insertion node following situations:

  1. Brothers parent node (ie uncle node) red
  2. Brothers parent node to node NULL (NULL default is black), and grandparent, parent node and the new node in a straight line
  3. Brothers parent node is NULL node and grandparent, parent node and the new node is not a straight line

Case 1:

The newly inserted parent node is red, when the parent node of the sibling nodes is red, the color balance adjustment operation.

At this time, the parent and sibling parent node (Node uncle) to black, the grandfather node (the parent's parent's) turns red, next to his grandfather repair node-based verification continues upwards, but in the end the root must black.

FIG: sequentially inserted into the node [200,100,300,50]

Case 1

Case 2:

Inserting a new parent node is red, sibling parent node is black, and the parent node, grandparent node and the new node three nodes in the same direction (a straight line), if left as a straight line (such as: and the "/" in the same direction), this time need dextrorotatory (for grandparent).

If a line-right (such as: and the "\" in the same direction), left at this time needs. Then the parent node of the new node becomes black, its sibling (the original grandparent) turns red.

FIG: sequentially inserted into the node [200,100,300,50,20] - In the case of right-handed Example

Case2

Case 3:

The case needs to be rotated twice.

新插入节点的父节点为红色,父节点的兄弟节点为黑色时,且父节点、祖父节点和新节点3个节点不在同一方向上(不是一条直线),如果新节点是父节点的右子节点(此时,父节点在祖父节点的左侧,此时这三个节点构成这样“<”方向非直线),此时需要先左旋(变为一条直线)再右旋,两次旋转。

如果新节点是父节点的左子节点(此时,父节点在祖父节点的右侧,此时这三个节点构成这样“>”方向非直线),此时需要先右旋(变为一条直线)再左旋,两次旋转。

可以发现,经过第一次旋转后,其实是被转变成了Case 2 的情况。

如图: 依次插入节点[200,100,300,50,80] - 以先左再右旋为例

Case3

伪代码- 插入元素平衡修正(来源Java TreeMap):

void fixAfterInsertion(Node<K,V> x) {
    // 新插入节点默认红色
    x.color = RED;
    // 不是根节点且父节点为红色
    while (x != null && x != root && x.parent.color == RED) {
        //父节点在祖父节点的左侧
        if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
            // 叔叔节点
            Node<K,V> y = rightOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                // 父节点设为黑色
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                // 祖父节点设为红色
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == rightOf(parentOf(x))) {
                    x = parentOf(x);
                    // 左旋
                    rotateLeft(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                // 右旋
                rotateRight(parentOf(parentOf(x)));
            }
        } else { // 对称的
            Node<K,V> y = leftOf(parentOf(parentOf(x)));
            if (colorOf(y) == RED) {
                setColor(parentOf(x), BLACK);
                setColor(y, BLACK);
                setColor(parentOf(parentOf(x)), RED);
                x = parentOf(parentOf(x));
            } else {
                if (x == leftOf(parentOf(x))) {
                    x = parentOf(x);
                    rotateRight(x);
                }
                setColor(parentOf(x), BLACK);
                setColor(parentOf(parentOf(x)), RED);
                rotateLeft(parentOf(parentOf(x)));
            }
        }
    }
    root.color = BLACK;
}

删除节点

红黑树的节点删除和二叉搜索树的节点删除过程是一样的,只是最后多了一步平衡纠正操作。

只有当删除黑色节点时需要平衡调整(删除红色节点时不需要平衡调整,没破坏红黑树规则),因删除黑色节点后,会违反从任意节点到叶子节点的每条路径包含的黑色节点数目相同的规则。

删除节点要比插入节点复杂些,插入节点整个过程是先找到插入节点位置 -> 插入节点 -> 平衡调整。而删除节点整个过程是先找到删除节点的位置 -> 节点的位置变换 -> 删除节点 -> 平衡调整,且调整的情况也相对较多。

前面说过,红黑树与二叉搜索树的删除节点过程一样,当删除节点存在两个子节点,会被转换为删除有一个子节点或不存在子节点的节点。
对于有一个子节点的节点删除,比较简单,不需要平衡调整,只需要将其子节点改为黑色即可。

如图: 依次插入节点[200,100,300,50]

Case 0

对于删除不存在子节点的节点,这种情况最为复杂,需要平衡调整。
删除节点平衡调整有如下几种情况:

  1. 待删除节点的兄弟节点是红色
  2. 待删除节点的兄弟节点是黑色,且兄弟节点的子节点都是黑色
  3. 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的左子节点是红色,右子节点是黑色。如果兄弟节点在左侧,就是兄弟节点的右子节点是红色,左节点是黑色
  4. 待删除节点的兄弟节点是黑色,如果兄弟节点在右侧,且兄弟节点的右子节点是红色,左子节点是任意颜色。如果兄弟节点在左侧,则就是兄弟节点的左子节点是红色,右子节点是任意色

Case 1:

对于 Case 1,首先改变父节点和兄弟节点颜色(兄弟节点变为黑色,父节点变为红色),再对父节点做一次旋转(红色的兄弟节点在右侧,左旋。红色的兄弟节点在左侧,右旋),操作后,红黑的规则没有被破坏,树的黑色高度没变化,原兄弟节点的一个子节点变成删除节点的新兄弟节点。

所以,Case 1 转化成了 Case 2 或 Case 3、Case 4 几种情况。

如图: 依次插入节点[200,100,300,400,500,600] - Case1 转换为 Case2,3,4 等情况

Case 1

Case 2:

对于Case 2,删除节点后其父节点的左子树比右子树黑高度小1,此时需要把兄弟节点改为红色,则左右子树黑高度就相同了。此时将删除节点的父节点变为新的节点,然后继续向上迭代调整,修正平衡。

如图: 依次插入节点[200,100,300,400,删除400] 得到下图结构

Case 2

Case 3:

对于Case 3,兄弟节点在右侧时,交换兄弟节点和其左子节点(红色)的颜色,并对兄弟节点进行右旋,于是被删除节点的新兄弟是一个有红色右子节点的黑色节点。相反,兄弟节点在左侧时,交换兄弟节点和其右子节点(红色)的颜色,并对兄弟节点进行左旋,于是被删除节点的新兄弟是一个有红色左子节点的黑色节点。
所以,Case 3 转化成了Case 4。

如图: 依次插入节点[200,100,300,250]

Case 3

Case 4:

For Case 4, when the right side of sibling, sibling and parent swap colors, right child node of fraternal set to black, and delete nodes of the parent node to do a left rotation.
Sibling nodes on the left side, sibling and parent swap colors, the left child node to node cronies black, and delete nodes of the parent node to do a right rotation.

Finally, delete the root node point directly to the end of the cycle.

FIG: sequentially inserted into the node [200,100,300,400]

Case 4

Pseudo code - remove elements balance correction (Source Java TreeMap):

void fixAfterDeletion(Node<K,V> x) {
    while (x != root && colorOf(x) == BLACK) {
        if (x == leftOf(parentOf(x))) {
            Node<K,V> sib = rightOf(parentOf(x));
            // Case 1
            if (colorOf(sib) == RED) {
                setColor(sib, BLACK);
                setColor(parentOf(x), RED);
                rotateLeft(parentOf(x));
                sib = rightOf(parentOf(x));
            }
            // Case 2
            if (colorOf(leftOf(sib))  == BLACK &&
                colorOf(rightOf(sib)) == BLACK) {
                setColor(sib, RED);
                x = parentOf(x);
            } else {
                // Case 3
                if (colorOf(rightOf(sib)) == BLACK) {
                    setColor(leftOf(sib), BLACK);
                    setColor(sib, RED);
                    rotateRight(sib);
                    sib = rightOf(parentOf(x));
                }
                // Case 4
                setColor(sib, colorOf(parentOf(x)));
                setColor(parentOf(x), BLACK);
                setColor(rightOf(sib), BLACK);
                rotateLeft(parentOf(x));
                x = root;
            }
        } else { // 对称的
            Node<K,V> sib = leftOf(parentOf(x));

            if (colorOf(sib) == RED) {
                setColor(sib, BLACK);
                setColor(parentOf(x), RED);
                rotateRight(parentOf(x));
                sib = leftOf(parentOf(x));
            }

            if (colorOf(rightOf(sib)) == BLACK &&
                colorOf(leftOf(sib)) == BLACK) {
                setColor(sib, RED);
                x = parentOf(x);
            } else {
                if (colorOf(leftOf(sib)) == BLACK) {
                    setColor(rightOf(sib), BLACK);
                    setColor(sib, RED);
                    rotateLeft(sib);
                    sib = leftOf(parentOf(x));
                }
                setColor(sib, colorOf(parentOf(x)));
                setColor(parentOf(x), BLACK);
                setColor(leftOf(sib), BLACK);
                rotateRight(parentOf(x));
                x = root;
            }
        }
    }

    setColor(x, BLACK);
}

Snippet article all from the Java TreeMap collection (with slight changes), this is the definitive reference.

Why choose many applications as the balanced red-black tree tree

When you insert or delete nodes, balanced binary tree in order to maintain a balance, a balance needs to be corrected, which requires a large overhead.

For example, a kind of AVL tree, is highly balanced tree structure is more balanced than the red-black tree, this also means that its easier to add or delete nodes imbalances, imbalances need to correct, add or delete a node when the overhead will be larger than the red-black tree. But it is undeniable efficiency AVL tree search is very stable.

Therefore, when large amounts of data need to insert or delete, AVL need balance adjustment frequency will be higher. Therefore, in the red-black tree insert and delete nodes requires a lot of scenes, more efficient. Naturally, due to the AVL-balanced, and therefore slightly higher AVL's Search efficiency.

Red-black tree is not highly balanced tree, but the effect has been very good balance. Therefore, it is considered a red-black tree is a compromise choice, better its overall performance.

At last

Red-black tree introduced to this end, the learning process can TreeMap reference source to learn, have unexpected results!


Recommended:
red-black tree data structures - moving map presentation (on)

Reference:
the JDK TreeMap source
https://www.zhihu.com/question/20545708

Guess you like

Origin www.cnblogs.com/newobjectcc/p/11295652.html