31-二叉排序树
1. 引入
给你一个数列 {7, 3, 10, 12, 5, 1, 9},要求能够高效的完成对数据的查询和添加。
1. 使用数组
- 数组未排序
- 优点:直接在数组尾部添加,速度快
- 缺点:查找速度慢
 
- 数组排序
- 优点:可以使用二分查找,查找速度快
- 缺点:为了保证数组有序,在添加新数据时,找到插入位置后,后面的数据需整体移动,速度慢
 
2. 使用链表
不管链表是否有序,查找速度都慢,添加数据速度比数组快,不需要数据整体移动
3. 使用二叉排序树
2. BST 介绍
- 二叉排序/搜索树(Binary Sort/Search Tree,简称 BST),对于二叉排序树的任何一个非叶子结点,要求:
- 左子结点的值比当前结点的值小
- 右子结点的值比当前结点的值大
 
- 特别说明:如果有相同的值,可以将该节点放在左子结点或右子结点
- 比如针对前面的数据 {7, 3, 10, 12, 5, 1, 9},对应的二叉排序树为:
  
3. BST 删除结点
3.1 删除叶子结点
- 找到待删除的结点 targetNode
- 找到 targetNode 的父结点
- 确定 targetNode 是 parent 的左子结点,还是右子结点
- 根据 step3 来进行删除
3.2 删除只有一颗子树的结点
- 找到待删除的结点 targetNode
- 找到 targetNode 的父结点 parent
- 确定 targetNode 是父结点的左子结点还是右子结点
- 确定 targetNode 的子结点是左子结点还是右子结点
- 分 4 种情况// 父之左 & 子在左 parent.left = targetNode.left; // 父之左 & 子在右 parent.left = targetNode.right; // 父之右 & 子在左 parent.right = targetNode.left; // 父之右 & 子在右 parent.right = targetNode.right;
3.3 删除有两颗子树的结点
- 找到待删除的结点 targetNode
- 找到 targetNode 的父结点 parent
- 从 targetNode 的右(左)子树中找出 value 最小(大)的结点
- 用一个临时变量 temp 来保存该最小(大)结点的 value
- 删除该最小(大)结点,并让 targetNode.value = temp // 可以理解为:用 targetNode 的右(左)子树中的最小(大)结点来替代 targetNode
4. 代码实现
class BinarySortTree {
    Node root;
    public void add(Node node) {
        if (root == null) root = node;
        else root.add(node);
    }
    public void infixOrder() {
        if (root != null) root.infixOrder();
        else System.out.println("空树");
        System.out.println();
    }
    public Node searchNode(int value) {
        if (root == null) return null;
        else return root.searchNode(value);
    }
    public Node searchParent(int value) {
        if (root == null || value == root.value) return null;
        else return root.searchParent(value);
    }
    /**
     * 删除node的最小value子结点, 并返回该最小结点的value
     * @param node 二叉排序树的根结点
     * @return 以node为根结点的二叉排序树的最小值
     */
    public int delTreeMinNode(Node node) {
        Node target = node;
        // 循环的查找左子结点
        while (target.left != null) target = target.left;
        // 这时, target就指向了最小结点
        delNode(target.value);
        return target.value;
    }
    /**
     * 删除node的最大value子结点, 并返回该最大结点的value
     * @param node 二叉排序树的根结点
     * @return 以node为根结点的二叉排序树的最小值
     */
    public int delTreeMaxNode(Node node) {
        Node target = node;
        // 循环的查找右子结点
        while (target.right != null) target = target.right;
        // 这时, target就指向了最小结点
        delNode(target.value);
        return target.value;
    }
    public void delNode(int value) {
        if (root == null) return;
        // 1. 找到待删除结点
        Node targetNode = searchNode(value);
        // a. 待删除结点不存在
        if (targetNode == null) return;
        // b. 存在, 是根结点,且这颗树只有这 1 个结点
        if (root.left == null && root.right == null) {
            root = null;
            return;
        }
        // 2. 找待删除结点的父结点
        Node parent = searchParent(value);
        // 3. 删除
        if (targetNode.left == null && targetNode.right == null) { // 3.1 叶子结点
            // 判断 targetNode 是 parent 的左子结点还是右子结点
            if (parent.left != null && parent.left.value == value)
                parent.left = null;
            else if (parent.right != null && parent.right.value == value)
                parent.right = null;
        } else if (targetNode.left != null && targetNode.right != null) { // 3.2 双子结点
            // a. 删除 targetNode 的右子树中 value 最小的结点, 并将其 value 赋值给 targetNode
            targetNode.value = delTreeMinNode(targetNode.right);
            // b. 删除 targetNode 的左子树中 value 最大的结点, 并将其 value 赋值给 targetNode
            // targetNode.value = delTreeMaxNode(targetNode.left);
        } else { // 3.3 单子结点
            if (parent.left != null && parent.left.value == value) { // 父之左
                if (targetNode.left != null) { // 子在左
                    parent.left = targetNode.left;
                } else { // 子在右
                    parent.left = targetNode.right;
                }
            } else { // 父之右
                if (targetNode.left != null) { // 子在左
                    parent.right = targetNode.left;
                } else { // 子在右
                    parent.right = targetNode.right;
                }
            }
        }
    }
}
class Node {
    int value;
    Node left;
    Node right;
    public Node(int value) {
        super();
        this.value = value;
    }
    // 查找结点
    public Node searchNode(int value) {
        if (value == this.value) {
            return this;
        } else if(value < this.value) {
            if (this.left != null) return this.left.searchNode(value);
            else return null;
        } else {
            if (this.right != null) return this.right.searchNode(value);
            else return null;
        }
    }
    /**
     * 查找某个结点的父结点
     * @param value 子结点的value
     * @return 父结点
     */
    public Node searchParent(int value) {
        if ((this.left != null && this.left.value == value)
                || (this.right != null && this.right.value == value)) {
            return this;
        } else {
            if (value < this.value && this.left != null)
                return this.left.searchParent(value);
            else if (value > this.value && this.right != null)
                return this.right.searchParent(value);
            else
                return null;
        }
    }
    // (递归)添加结点
    public void add(Node node) {
        if (node == null) return;
        // 判断node的value和当前子树根结点的value的大小关系
        if (node.value < this.value) {
            if (this.left != null) his.left.add(node);
            else this.left = node;
        } else {
            if (this.right != null) this.right.add(node);
            else this.right = node;
        }
    }
    // 中序遍历
    public void infixOrder() {
        if (this.left != null) this.left.infixOrder();
        System.out.print(this + " ");
        if (this.right != null) this.right.infixOrder();
    }
    @Override
    public String toString() {
        return "[value=" + value + "]";
    }
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号