1.4.3.4 RB Tree Delete Implementation

完整的原始碼點我

刪除的主要邏輯:

public boolean delete(int key) {
        // 1: Find the node you want to delete
        RbNode current = root;
        RbNode parent = root;

        // The substitution of the deleted node
        RbNode substitution = null;

        current = this.findOneNode(root, key);
        if (current == null) {
            return true;
        }
        parent = current.getParent();

        // 2: If the node has no child
        if ((current.getLeft() == null || isEmptyNode(current.getLeft()))
                && (current.getRight() == null || isEmptyNode(current.getRight()))) {
            hasNoChildren(parent, current, isLeft);
            if (!current.isRed()) {
                substitution = new RbNode(SUBSTITUTION_ID, SUBSTITUTION_DATA, false);
                substitution.setParent(current.getParent());

                if (parent != null) {
                    if (isLeft) {
                        parent.setLeft(substitution);
                    } else {
                        parent.setRight(substitution);
                    }
                }

            }
            current.setParent(null);
        }
        // 3: If the node has only one child
        // 3.1: Only has left child
        else if (current.getRight() == null || isEmptyNode(current.getRight())) {
            oneLeftChild(parent, current, isLeft);
            if (!current.isRed() && current.getLeft().isRed()) {
                current.getLeft().setRed(false);
            } else if (!current.isRed() && !current.getLeft().isRed()) {
                substitution = current.getLeft();
            }
        }
        // 3.2: Only has right child
        else if (current.getLeft() == null || isEmptyNode(current.getLeft())) {
            oneRightChild(parent, current, isLeft);
            if (!current.isRed() && current.getRight().isRed()) {
                current.getRight().setRed(false);
            } else {
                substitution = current.getRight();
            }
        }
        // 4: If the node has two child
        else {
            // 4.1: Find the in-order successor
            RbNode successor = getSuccessor(current);

            /*
             * 4.2: Swap the successor and current node without copying color and changing
             * relationship
             */
            RbNode tempNode = new RbNode(successor.getId(), successor.getData(), successor.isRed());
            successor.setId(current.getId());
            successor.setData(current.getData());

            current.setId(tempNode.getId());
            current.setData(tempNode.getData());

            // 4.3: Execute delete operation again
            delete(successor.getId());
        }

        // After the delete operation, execute balance operation
        if (substitution != null) {
            balanceAfterDelete(substitution);
        }

        return true;
    }

在刪除過程中搜尋節點:

private RbNode findOneNode(RbNode node, int key) {
        if (node != null) {
            if (node.getId() == key) {
                return node;
            }

            RbNode tempNode = findOneNode(node.getLeft(), key);
            if (tempNode != null) {
                if (tempNode == tempNode.getParent().getLeft()) {
                    isLeft = true;
                } else {
                    isLeft = false;
                }
                return tempNode;
            }

            tempNode = findOneNode(node.getRight(), key);
            if (tempNode != null) {
                if (tempNode == tempNode.getParent().getLeft()) {
                    isLeft = true;
                } else {
                    isLeft = false;
                }
                return tempNode;
            }
        }
        return null;
    }

刪除之後的平衡操作:

private void balanceAfterDelete(RbNode currentNode) {
        if (currentNode.isRed()) {
            currentNode.setRed(false);
        } else if (currentNode.getParent() == null) {
            currentNode.setRed(false);
        } else if (!currentNode.isRed()) {
            RbNode bNode = (currentNode == currentNode.getParent().getLeft()) ? 
            currentNode.getParent().getRight() : currentNode.getParent().getLeft();

            if (bNode.isRed() && currentNode == currentNode.getParent().getLeft()) {
                bNode.setRed(currentNode.getParent().isRed());
                currentNode.getParent().setRed(true);
                leftRotate(currentNode.getParent());
                balanceAfterDelete(currentNode);
            } else if (bNode.isRed() && currentNode == currentNode.getParent().getRight()) {
                bNode.setRed(currentNode.getParent().isRed());
                currentNode.getParent().setRed(true);
                rightRotate(currentNode.getParent());
                balanceAfterDelete(currentNode);
            } else if (bNode.isRed() && !currentNode.getParent().isRed() 
                    && (bNode.getLeft() == null || !bNode.getLeft().isRed())
                    && (bNode.getRight() == null || !bNode.getRight().isRed())) {
                bNode.setRed(true);
                currentNode = currentNode.getParent();
                balanceAfterDelete(currentNode);
            } else if (!bNode.isRed() && currentNode.getParent().isRed() 
                    && (bNode.getLeft() == null || !bNode.getLeft().isRed())
                    && (bNode.getRight() == null || !bNode.getRight().isRed())) {
                bNode.setRed(true);
                currentNode.getParent().setRed(false);
            } else if (!bNode.isRed() && (currentNode == currentNode.getParent().getLeft())
                    && (bNode.getLeft() != null && bNode.getLeft().isRed())
                    && (bNode.getRight() == null || !bNode.getRight().isRed())) {
                bNode.setRed(true);
                bNode.getLeft().setRed(false);
                rightRotate(bNode);
                balanceAfterDelete(currentNode);
            } else if (!bNode.isRed() && (currentNode == currentNode.getParent().getRight())
                    && (bNode.getRight() != null && bNode.getRight().isRed())
                    && (bNode.getLeft() == null || !bNode.getLeft().isRed())) {
                bNode.setRed(true);
                bNode.getRight().setRed(false);
                leftRotate(bNode);
                balanceAfterDelete(currentNode);
            } else if (!bNode.isRed() && (currentNode == currentNode.getParent().getLeft())
                    && (bNode.getRight() != null && bNode.getRight().isRed())) {
                bNode.setRed(currentNode.getParent().isRed());
                currentNode.getParent().setRed(false);
                bNode.getRight().setRed(false);
                leftRotate(currentNode.getParent());
            } else if (!bNode.isRed() && (currentNode == currentNode.getParent().getRight())
                    && (bNode.getLeft() != null && bNode.getLeft().isRed())) {
                bNode.setRed(currentNode.getParent().isRed());
                currentNode.getParent().setRed(false);
                bNode.getLeft().setRed(false);
                rightRotate(currentNode.getParent());
            }
        }
    }

Last updated