二叉排序树(BST)的创建和删除

1.二叉排序树介绍

二叉排序树:BST(Binary Sort Tree),对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,如右子节点的值当当前节点值大。如果有相同的值,可以将改节点放在左子节点或右子节点。
比如针对数据{7,3,10,12,5,1,9},对应的二叉排序树为:
在这里插入图片描述

2.二叉排序树的创建

2.1思路分析:
(1)先判断二叉排序树的根节点是否为空,如果为空则把当前节点复制给跟节点
(2)如果不为空,则进行添加操作
(3)进行添加操作时先判断当前节点的值是否大于添加节点,如果大于再判断当前节点左节点是否为空,如果为空则进行添加,如果不为空则进行递归操作
(4)如果当前节点小于添加节点,则判断当前节点的右子节点是否为空,如果为空则进行添加操作,如果不为空则进行递归操作
2.2代码演示

//二叉排序树
class BinarySortTree{
    //二叉排序树的根节点
    private Node root;

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    //创建二叉排序树
    public void add(Node node) {
        if (root == null) {
            root = node;
            return;
        }
        root.addNode(node);
    }
    //中序遍历
    public void infixOrder() {
        if (root != null) {
            root.infixOrder();
            return;
        }
        throw new NullPointerException("根节点为空");
    }
  
  }
 //二叉排序树的节点
class Node{
    private int value;
    private Node left;
    private Node right;
    public Node(int value) {
        this.value = value;
    }
    public Node() {}

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    /**
     * 向二叉排序树中添加节点
     * @param node 要添加的节点
     */
    public void addNode(Node node) {
        if (node == null) {
            throw new NullPointerException("节点为空");
        }
        //判断当前节点的值是否大于添加节点
        if (this.value > node.value) {
            //判断当前节点的左子节点是否为空
            if (this.left == null) {
                this.left = node;
                return;
            }
            //递归
            this.left.addNode(node);
            return;
        }
        //判断当前节点的右子节点是否为空
        if (this.right == null) {
            this.right = node;
            return;
        }
        //递归
        this.right.addNode(node);
    }
    //中序遍历
    public void infixOrder() {
        if (this.left != null) {
            this.left.infixOrder();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixOrder();
        }
    }
     @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                '}';
    }

 }

3.二叉排序树的删除

在这里插入图片描述
3.1思路分析
二叉排序树的删除情况比较复杂,有下面6种情况要考虑
(1)删除叶子节点(比如2,5,9,12)
(2)删除只有一个子节点的节点(比如1)
(3)删除有两颗子节点的节点(比如7,3,10)
(4)删除叶子节点为根节点时
(5)删除只有一个子节点的节点为根节点
(6)删除有两颗子节点的节点为根节点

第一种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)判断targetNode时parent的左子节点还是右子节点
(4)左子节点:parent.left = null,右子节点 parent.right = null
第二种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)判断targetNode时parent的左子节点还是右子节点
(4)判断targetNode的子节点是左子节点还是右子节点
(5)如果targetNode是parent的左子节点
(5.1)如果targetNode有左子节点parent.left = target.left
(5.2)如果targetNode有右子节点parent.left= target.right
(6)如果targetNode是parent的右子节点
(6.1)如果targetNode有左子节点parent.right= target.left
(6.2)如果targetNode有右子节点parent.right= target.right
第三种情况:
(1)先要找到要删除的节点targetNode
(2)再找到要删除节点的父节点parent
(3)从targetNode的左子树上找到最大的节点并复制给max
(4)删除最大节点
(5)max.left = targetNode.left
(6)max.right = targetNode.right
(7)如果如果targetNode是parent的左子节点,parent.left =max
(8)如果如果targetNode是parent的右子节点,parent.right=max
第四种情况:
直接把根节点置空,root = null
第五种情况:
(1)如果根节点左子节点,root = roo.left
(2)如果根节点右子节点,root = roo.right
第六种情况:
(1)从root的左子树上找到最大的节点并复制给max
(2)删除最大节点
(3)max.left = root.left
(4)max.right = root.right
(5) root = max
3.2代码实现

//查找要删除的节点
public Node search(int value) {
    if (this.root != null){
        return this.root.search(value);
    }
    throw new NullPointerException("根节点为空");
}
//查找要删除节点的父节点
public Node searchParent(int value) {
    if (this.root != null){
        return this.root.searchParent(value);
    }
    throw new NullPointerException("根节点为空");
}
//删除节点
public Node deleteNode(int value) {
    if (this.root != null){
        //需要先去找到要删除的节点
        Node targetNode = this.root.search(value);
        //找到要删除节点的父节点
        Node parent = this.root.searchParent(value);
        //表示没有找到要删除的节点
        if (targetNode == null) {
            return null;
        }
        //说明根节点就是要我们要删除的节点
        if (this.root.getLeft() == null && this.root.getRight() == null) {
            Node temp = this.root;
            this.root = null;
            return temp;
        }
        //说明根节点就是要我们要删除的节点,而根节点又有一个左子节点或右子节点
        if (this.root.getValue() == value &&
                (this.root.getLeft() == null || this.root.getRight() == null)) {
            //说明左节点不为空
            if (this.root.getLeft() != null) {
                Node temp = this.root;
                this.root = this.root.getLeft();
                return temp;
            }
            //说明右节点不为空
            Node temp = this.root;
            this.root = this.root.getRight();
            return temp;
        }
        //说明根节点就是要我们要删除的节点,而根节点又有一个左子节点和一个右子节点
        if (this.root.getValue() == value &&
                (this.root.getLeft() != null && this.root.getRight() != null)) {
            //需要从要删除节点的左子树上找到最大的节点,然后替换要删除的节点
            Node max = searchMax(this.root.getLeft());
            deleteNode(max.getValue());
            max.setLeft(this.root.getLeft());
            max.setRight(this.root.getRight());
            Node temp = this.root;
            this.root = max;
            return temp;
        }
        //说明要删除节点没有左右子节点,改要删除的节点是叶子节点
        if (targetNode.getLeft() == null && targetNode.getRight() == null) {
            //说明要删除是父节点的左节点
            if (parent.getValue() > targetNode.getValue()) {
                parent.setLeft(null);
                return targetNode;
            }
            //说明要删除是父节点的右节点
            parent.setRight(null);
            return targetNode;
        }
        //说明要删除节点有一个左子节点或右子节点
        if (targetNode.getLeft() == null || targetNode.getRight() == null) {
            //说明要删除是父节点的左节点
            if (parent.getValue() > targetNode.getValue()) {
                //说明要删除节点有一个左子节点
                if (targetNode.getLeft() != null) {
                    parent.setLeft(targetNode.getLeft());
                    return targetNode;
                }
                //说明要删除节点有一个右子节点
                parent.setLeft(targetNode.getRight());
                return targetNode;
            }
            //说明要删除节点有一个左子节点
            if (targetNode.getLeft() != null) {
                parent.setRight(targetNode.getLeft());
                return targetNode;
            }
            //说明要删除节点有一个右子节点
            parent.setRight(targetNode.getRight());
            return targetNode;
        }
        //说明要删除的节点有一个左子节点和一个右子节点
        if (targetNode.getLeft() != null && targetNode.getRight() != null) {
            //需要从要删除节点的左子树上找到最大的节点,然后替换要删除的节点
            Node max = searchMax(targetNode.getLeft());
            deleteNode(max.getValue());
            max.setLeft(targetNode.getLeft());
            max.setRight(targetNode.getRight());
            //说明要删除是父节点的左节点
            if (parent.getValue() > targetNode.getValue()) {

                parent.setLeft(max);
                return targetNode;
            }
            //说明要删除是父节点的右节点
            parent.setRight(max);
            return targetNode;
        }
    }
    throw new NullPointerException("根节点为空");
}
//寻找值最大的节点
public Node searchMax(Node node) {
    if (node != null) {
        return node.searchMax();
    }
    throw new NullPointerException("节点为空");
}


/**
 * 查找要删除的节点
 * @param value 希望删除的节点的值
 * @return 删除的节点
 */
public Node search(int value) {
    //找到了要删除的节点
    if (this.value == value) {
        return this;
    }
    //如果当前的节点的值大于要删除的节点的值,则向左递归查找
    if (this.value > value && this.left != null) {
        return this.left.search(value);
    }
    //如果当前的节点的值小于要删除的节点的值,则向右递归查找
    if (this.value <= value && this.right != null) {
        return this.right.search(value);
    }
    //没有查找到要删除的节点
    return null;
}

/**
 * 查找要删除节点的父节点
 * @param value 要删除节点的值
 * @return 删除节点的父节点
 */
public Node searchParent(int value) {
    //说明找到了父节点
    if ((this.left != null && this.left.value == value) ||
            (this.right != null && this.right.value == value)) {
        return this;
    }
    //向左递归查找
    if (this.left != null && this.value > value) {
        return this.left.searchParent(value);
    }
    //向右递归查找
    if (this.right != null && this.value <= value) {
        return this.right.searchParent(value);
    }
    //没有查找到父节点
    return null;
}
public Node searchMax() {
    if (this.getRight() != null) {
        return this.getRight().searchMax();
    }
    return this;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值