二叉排序树(BST)

参考文章

定义
一棵空树,或者是具有下列性质的二叉树:

1 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2) 若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3) 左、右子树也分别为二叉排序树;
4) 没有键值相等的结点。

代码实现如下,参考文章的图解和思路都超赞

/**
 * 二叉排序树节点
 */
public class BSTreeNode {

    /**
     * 树的标识
     */
    private int key;

    /**
     * 左子节点
     */
    private BSTreeNode leftNode;
    /**
     * 右子节点
     */
    private BSTreeNode rightNode;

    public BSTreeNode() {
    }

    public BSTreeNode(int key) {
        this.key = key;
    }

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public BSTreeNode getLeftNode() {
        return leftNode;
    }

    public void setLeftNode(BSTreeNode leftNode) {
        this.leftNode = leftNode;
    }

    public BSTreeNode getRightNode() {
        return rightNode;
    }

    public void setRightNode(BSTreeNode rightNode) {
        this.rightNode = rightNode;
    }

    @Override
    public String toString() {
        return "BSTreeNode{" +
                "key=" + key +
                '}';
    }

    /**
     * 添加子节点
     *
     * @param node
     */
    public void add(BSTreeNode node) {
        if (node == null) {
            return;
        }
        if (this.key == node.key) {
            System.out.println("该节点已存在");
            return;
        }
        //放在该节点的左边
        if (node.key < this.key) {
            //如果没有左子节点,那么就放左子节点
            if (this.leftNode == null) {
                this.leftNode = node;
            } else {
                //继续递归
                this.leftNode.add(node);
            }
        } else {
            //放在该节点的右边
            //如果没有右子节点,那么就放右子节点
            if (this.rightNode == null) {
                this.rightNode = node;
            } else {
                //继续递归
                this.rightNode.add(node);
            }
        }

    }
    
}



/**
 * 二叉排序树(二叉搜索树 BinarySearchTree)
 * <p>
 * 实现功能
 * 1.添加
 * 2.查找
 * 3.删除
 */
public class BSTree {

    /**
     * 根节点
     */
    private BSTreeNode root;

    /**
     * 添加节点
     *
     * @param node
     */
    public void add(BSTreeNode node) {
        if (root == null) {
            root = node;
            return;
        }

        //添加
        root.add(node);
    }


    /**
     * 删除节点
     *
     * @param key
     */
    public void delete(int key) {
        BSTreeNode parent = searchParent(key);
        if (parent == null) {
            System.out.println("parent未找到");
            return;
        }

        //找到等待删除的节点
        BSTreeNode target;
        //跟parent的子节点进行比对
        if (parent.getLeftNode() != null && parent.getLeftNode().getKey() == key) {
            target = parent.getLeftNode();
        } else {
            target = parent.getRightNode();
        }


        System.out.println("key=" + key + "parent=" + parent + "target=" + target);

        //那么就有三种情况
        //1.待删除节点是叶子节点,那么就直接删
        //2.待删除节点下有单个子节点,那么就节点上移
        //3.待删除节点下存在两个子节点,那么就把右子节点下最小的值上移
        int num = getChildNum(target);
        //分别出来三种情况
        if (num == 0) {
            //进入情况1
            //如果是左节点就删除左节点,是右节点就删除右节点
            if (target == parent.getLeftNode()) {
                parent.setLeftNode(null);
            } else {
                parent.setRightNode(null);
            }

        } else if (num == 1) {
            //情况2

            //如果是左节点就删除左节点的子节点上提,是右节点就上提右子节点的子节点
            BSTreeNode child = getSingleChild(target);
            if (target == parent.getLeftNode()) {
                parent.setLeftNode(child);
            } else {
                parent.setRightNode(child);
            }


        } else {
            //情况3  ,待删除的子节有两个子节点
            //找出右子节点下最小的那个节点,替换到待删除节点
            BSTreeNode minChild = getMinChild(target);
            //删除该节点
            delete(minChild.getKey());
            //然后替换,完成
            target.setKey(minChild.getKey());
        }
    }

    /**
     * 遍历查询子数下最小的节点
     *
     * @param target
     * @return
     */
    private BSTreeNode getMinChild(BSTreeNode target) {
        BSTreeNode temp = target.getLeftNode();
        while (temp.getLeftNode() != null) {
            temp = temp.getLeftNode();
        }
        return temp;
    }


    /**
     * 获取唯一的孩子节点
     *
     * @param target
     * @return
     */
    private BSTreeNode getSingleChild(BSTreeNode target) {
        //左子节点存在就返回,否则返回右子节点
        return target.getLeftNode() != null ? target.getLeftNode() : target.getRightNode();
    }


    /**
     * 获取该节点左右子节点的个数
     *
     * @param node
     * @return
     */
    private int getChildNum(BSTreeNode node) {
        int num = 0;
        //存在左子节点
        if (node.getLeftNode() != null) {
            num++;
        }
        //存在右子节点
        if (node.getRightNode() != null) {
            num++;
        }
        return num;
    }


    /**
     * 搜索
     *
     * @param key
     * @return
     */
    public BSTreeNode search(int key) {
        if (null == root) {
            return null;
        }
        BSTreeNode node = root;
        while (node != null) {
            int match = node.getKey();
            if (key == match) {
                return node;
            }
            if (key < match) {
                node = node.getLeftNode();
            } else {
                node = node.getRightNode();
            }
        }
        return null;
    }


    /**
     * 搜索待删除节点的父节点
     *
     * @param key
     * @return
     */
    public BSTreeNode searchParent(int key) {
        if (null == root) {
            return null;
        }

        BSTreeNode temp = root;
        while (temp != null) {
            //跟它的子节点进行匹配,匹配任意一个都好使
            if ((temp.getLeftNode() != null && temp.getLeftNode().getKey() == key)
                    || (temp.getRightNode() != null && temp.getRightNode().getKey() == key)) {
                return temp;
            }
            //不匹配的话,继续查找
            int match = temp.getKey();
            if (key < match) {
                temp = temp.getLeftNode();
            } else {
                temp = temp.getRightNode();
            }
        }
        return null;
    }

    /**
     * 中序遍历
     */
    public void midTraverse() {
        if (root == null) {
            return;
        }
        midTraverse(root);
    }

    /**
     * 中序遍历
     *
     * @param node
     */
    private void midTraverse(BSTreeNode node) {
        if (node.getLeftNode() != null) {
            midTraverse(node.getLeftNode());
        }
        System.out.println(node);
        if (node.getRightNode() != null) {
            midTraverse(node.getRightNode());
        }
    }
}



  /**
     * 测试代码
     * @param args
     */
    public static void main(String[] args) {
        int[] array = new int[]{50, 30, 80, 20, 35, 34, 32, 40, 70, 75, 100};
        BSTree tree = new BSTree();
        for (int i = 0; i < array.length; i++) {
            int key = array[i];
            BSTreeNode node = new BSTreeNode(key);
            tree.add(node);
        }
        System.out.println("中序遍历");
        tree.midTraverse();
        System.out.println("搜索20=" + tree.search(20));
        System.out.println("搜索200=" + tree.search(200));
        //删除节点
        tree.delete(30);
        System.out.println("中序遍历");
        tree.midTraverse();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值