1. 程式人生 > 實用技巧 >二叉排序樹刪除

二叉排序樹刪除


二叉排序樹的刪除情況比較複雜,有以下三種情況需要考慮

  • 刪除葉子節點(比如:2,5,9,12)
  • 刪除只有一棵子樹的節點(比如1)
  • 刪除有兩棵子樹的節點(比如:7,3,10)
  • 操作思路分析

第一種情況:刪除葉子節點

思路:

    1. 需要先找到待刪除的節點 targetNode
    1. 找到targetNode的父節點 parent
    1. 確定targetNode是parent的左節點還是右節點
    1. 根據左右來進行刪除
    • 左子節點 parent.left = null
    • 右子節點 parent.right = null

第二種情況:刪除只有一棵子樹的節點,比如1

思路:

    1. 需要先找到待刪除的節點targetNode
    1. 找到targetNode的父節點 parent
    1. 確定targetNode的子節點是左子節點還是又子節點
    1. targetNode是parent的左子節點還是右子節點
    1. 如果targetNode有左子節點
    • 5.1. 如果targetNode是parent的左子節點 parent.left = targetNode.left
    • 5.2. 如果targetNode是parent的右子節點 parent.right = targetNode.left
    1. 如果targetNode有右子節點
    • 6.1. 如果targetNode是parent的左子節點 parent.left = targetNode.right
    • 6.2 如果targetNode是parent的右子節點 parent.right = targetNode.right

第三種情況:刪除有兩棵子樹的節點(比如:7,3,10)

思路:

    1. 需要先找到待刪除的節點 targetNode
    1. 找到targetNode的父節點 parent
    1. 從targetNode的右子樹中找到最小的節點
    1. 用一個臨時變數,將最小的節點值儲存在temp中
    1. 刪除該最小的節點
    1. targetNode.val = temp
public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int[] arr = {7, 3, 10, 12, 5, 1, 9,2};
        BinarySortTree binarySortTree = new BinarySortTree();
        for (int i = 0; i < arr.length; i++) {
            binarySortTree.addNode(new Node(arr[i]));
        }
        //遍歷
        binarySortTree.midOrder();

        //測試刪除節點
        binarySortTree.delNode(5);
        binarySortTree.delNode(9);
        binarySortTree.delNode(10);
        binarySortTree.delNode(12);
        binarySortTree.delNode(7);
        binarySortTree.delNode(1);
        binarySortTree.delNode(2);
        binarySortTree.delNode(3);

        System.out.println("刪除後");
        binarySortTree.midOrder();
    }
}

class BinarySortTree {
    private Node root;

    //新增節點
    public void addNode(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.addNode(node);
        }
    }

    //中序遍歷節點
    public void midOrder() {
        if (root == null) {
            System.out.println("二叉排序樹為空");
        } else {
            root.midOrder();
        }
    }

    //查詢待刪除的節點
    public Node searchNode(int val) {
        if (this.root == null) {
            return null;
        } else {
            return this.root.serachNode(val);
        }
    }

    //查詢待刪除的父節點
    public Node searchParentNode(int val) {
        if (this.root == null) {
            return null;
        } else {
            return this.root.searchParentNode(val);
        }
    }
    //在待查詢二叉樹中找到最小的節點
    public int searchRightMin(Node node){
        while (node.left != null){
            node = node.left;
        }
        delNode(node.val);  //刪除最小的節點
        return node.val;  //返回最小的節點值
    }
    //刪除節點
    public void delNode(int val) {
        if (this.root == null) {
            return;
        } else {
            //先拿到待刪除的節點
            Node targetNode = searchNode(val);
            if (targetNode == null) {
                return;
            }
            //如果這棵二叉樹只有一個節點
            if (this.root.left == null && this.root.right == null) {
                if (root.val == val) {
                    root = null;
                    return;
                }
            }
            //拿到待刪除節點的父節點
            Node parent = searchParentNode(val);
            //如果刪除的葉子節點
            if (targetNode.left == null && targetNode.right == null) {
                //判斷targetNode是parent的左節點還是右節點
                if (parent.left != null && parent.left.val == val) {
                    parent.left = null;
                } else if (parent.right != null && parent.right.val == val) {
                    parent.right = null;
                }
            } else if (targetNode.left != null && targetNode.right != null) { // 如果刪除的是帶有兩個葉子節點的節點
                //從targetNode的右子樹中找到最小的節點
                int temp = searchRightMin(targetNode.right);
                targetNode.val = temp;
            }else {  //待刪除節點有一個分支
                //如果待刪除的節點有左節點
                if (targetNode.left !=null){
                    //待刪除的是根節點
                    if (parent == null){
                        this.root = targetNode.left;
                    }else {
                        //待刪除的節點是左節點
                        if (parent.left!=null && parent.left.val == val){
                            parent.left = targetNode.left;
                        }else if(parent.right!=null && parent.right.val == val){ // 待刪除的節點是右節點
                            parent.right = targetNode.left;
                        }
                    }
                }else { //待刪除的節點有有分支
                    if (parent == null){
                        this.root = targetNode.right;
                    }else {
                        if (parent.left!=null && parent.left.val == val){
                            parent.left = targetNode.right;
                        }else if (parent.right!=null && parent.right.val == val){
                            parent.right = targetNode.right;
                        }
                    }
                }
            }
        }
    }
}

class Node {

    int val;
    Node left;
    Node right;

    public Node(int val) {
        this.val = val;
    }

    @Override
    public String toString() {
        return "Node{" +
                "val=" + val +
                '}';
    }

    //查詢待刪除節點的父節點
    public Node searchParentNode(int val) {
        if ((this.left != null && this.left.val == val) || (this.right != null && this.right.val == val)) {
            return this;
        } else {
            if (this.val > val && this.left != null) {
                return this.left.searchParentNode(val);
            } else if (this.val <= val && this.right != null) {
                return this.right.searchParentNode(val);
            } else {
                return null;
            }
        }
    }

    //查詢到待刪除的節點
    public Node serachNode(int val) {
        if (this.val == val) {
            return this;
        } else if (this.val > val) {
            if (this.left != null) {
                return this.left.serachNode(val);
            } else {
                return null;
            }
        } else {
            if (this.right != null) {
                return this.right.serachNode(val);
            } else {
                return null;
            }
        }
    }

    //新增節點
    public void addNode(Node node) {
        if (this.val > node.val) {
            //需要掛載到左邊
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.addNode(node);
            }
        } else {
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.addNode(node);
            }
        }
    }

    //中序遍歷
    public void midOrder() {
        if (this.left != null) {
            this.left.midOrder();
        }
        System.out.println(this.val);
        if (this.right != null) {
            this.right.midOrder();
        }
    }
}