1.4.3.2 RB Tree Insertion Implementation

完整的原始碼點我

這邊是insert的部分:

public void insert(int id, int data) {
        // Create a new node
        RbNode newNode = new RbNode(id, data, true);

        if (root == null) {
            root = newNode;
        } else {
            // Find the insert location
            RbNode current = root;
            RbNode parent = null;

            while (true) {
                parent = current;
                if (id < current.getId()) {
                    current = current.getLeft();
                    // If no left
                    if (current == null) {
                        // Modify related node's attribute
                        parent.setLeft(newNode);
                        newNode.setParent(parent);
                        break;
                    }
                } else {
                    current = current.getRight();
                    // If no right
                    if (current == null) {
                        // Modify related node's attribute
                        parent.setRight(newNode);
                        newNode.setParent(parent);
                        break;
                    }
                }
            }
        }

        balanceAfterInsert(newNode);
    }

這邊是平衡的部分:

private void balanceAfterInsert(RbNode currentNode) {
        /*
         * Case 1: If the node is root, this will violate the rule
         * that the root should be black, so change the node to black.
         */
        if (currentNode.getParent() == null) {
            currentNode.setRed(false);
            root = currentNode;
        } else
        /*
         * Case 2: If node P is black, do nothing since it already match the rule.
         */
        if (!currentNode.getParent().isRed()) {
            // Do nothing.
        } else if (currentNode.getParent().isRed()) {
            RbNode gNode = currentNode.getParent().getParent();
            RbNode uNode = null;
            if (gNode != null) {
                uNode = (gNode.getLeft() == currentNode.getParent()) ? gNode.getRight() : gNode.getLeft();
            }
            /*
             * Case 3: If node P and node U are all red, modify node G to red and modify both node P
             * and node U to black, then set the node G as current node and perform
             * balanceAfterInsert
             * operation on it.
             */
            if (uNode != null && uNode.isRed()) {
                gNode.setRed(true);
                uNode.setRed(false);
                currentNode.getParent().setRed(false);
                currentNode = gNode;
                balanceAfterInsert(currentNode);
            } else if (uNodeIsBlackOrNull(uNode)) {
                /*
                 * Case 4: If node P is red and node U is black, and the inserted node is the left
                 * of node P, and the node P is the left of node G, then modify the node P to black,
                 * and modify the node G to red. Finally, perform right rotate on node G and
                 * balanceAfterInsert
                 * on current node.
                 */
                if (currentNode == currentNode.getParent().getLeft()
                        && (gNode != null && currentNode.getParent() == gNode.getLeft())) {
                    currentNode.getParent().setRed(false);
                    gNode.setRed(true);
                    rightRotate(gNode);
                    balanceAfterInsert(currentNode);
                } else
                /*
                 * Case 5: If node P is red and node U is black, and the inserted node is the right
                 * of node P, and the node P is the right of node G, then modify the node P to
                 * black, and modify the node G to red. Finally, perform left rotate on node G and
                 * balanceAfterInsert on current node.
                 */
                if (currentNode == currentNode.getParent().getRight()
                        && (gNode != null && currentNode.getParent() == gNode.getRight())) {
                    currentNode.getParent().setRed(false);
                    gNode.setRed(true);
                    leftRotate(gNode);
                    balanceAfterInsert(currentNode);
                } else
                /*
                 * Case 6: If node P is red and node U is black, and the inserted node is the right
                 * of node P, and the node P is the left of node G, then let the node P be the new
                 * current node. Finally, perform left rotate on the current node and
                 * balanceAfterInsert on it
                 */
                if (currentNode == currentNode.getParent().getRight()
                        && (gNode != null && currentNode.getParent() == gNode.getLeft())) {
                    RbNode oldParent = currentNode.getParent();
                    leftRotate(oldParent);
                    balanceAfterInsert(oldParent);
                } else
                /*
                 * Case 7:If node P is red and node U is black, and the inserted node is the left of
                 * node P, and the node P is the right of node G, then let the node P be the new
                 * current node. Finally perform right rotate on the current node and
                 * balanceAfterInsert on it
                 */
                if (currentNode == currentNode.getParent().getLeft()
                        && (gNode != null && currentNode.getParent() == gNode.getRight())) {
                    RbNode oldParent = currentNode.getParent();
                    rightRotate(oldParent);
                    balanceAfterInsert(oldParent);
                }
            }
        }
    }

    private boolean uNodeIsBlackOrNull(RbNode uNode) {
        return (uNode == null || !uNode.isRed());
    }

這邊是左旋轉的部分:

private void leftRotate(RbNode pivot) {
        RbNode oldRight = pivot.getRight();
        RbNode leftOfOldRight = null;
        if (oldRight != null) {
            leftOfOldRight = oldRight.getLeft();
        }

        if (pivot.getParent() != null) {
            // Determine it's the left ot right
            boolean isLeft = (pivot.getParent().getLeft() == pivot);
            if (isLeft) {
                pivot.getParent().setLeft(oldRight);
            } else {
                pivot.getParent().setRight(oldRight);
            }

            if (oldRight != null) {
                oldRight.setParent(pivot.getParent());
            }
        } else {
            oldRight.setParent(null);
            oldRight.setRed(false);
            root = oldRight;
        }

        if (oldRight != null) {
            oldRight.setLeft(pivot);
        }
        pivot.setParent(oldRight);

        pivot.setRight(leftOfOldRight);
        if (leftOfOldRight != null) {
            leftOfOldRight.setParent(pivot);
        }
    }

這邊是右旋轉的部分:

private void rightRotate(RbNode pivot) {
        RbNode oldLeft = pivot.getLeft();
        RbNode rightOfOldLeft = null;
        if (oldLeft != null) {
            rightOfOldLeft = oldLeft.getRight();
        }
        if (pivot.getParent() != null) {
            // Determine it's the left ot right
            boolean isLeft = (pivot.getParent().getLeft() == pivot);
            if (isLeft) {
                pivot.getParent().setLeft(oldLeft);
            } else {
                pivot.getParent().setRight(oldLeft);
            }

            if (oldLeft != null) {
                oldLeft.setParent(pivot.getParent());
            }
        } else {
            oldLeft.setParent(null);
            oldLeft.setRed(false);
            root = oldLeft;
        }

        if (oldLeft != null) {
            oldLeft.setRight(pivot);
        }
        pivot.setParent(oldLeft);

        pivot.setLeft(rightOfOldLeft);
        if (rightOfOldLeft != null) {
            rightOfOldLeft.setParent(pivot);
        }
    }

Last updated