Java实现二叉搜索树

Java实现二叉搜索树

一、二叉搜索树概念

​ 二叉搜索树(Binary Search Tree,BST),相比与普通树,有以下四点性质

  • 非空左子树的所有键值小于其根结点的键值;
  • 非空右子树的所有键值大于其根结点的键值;
  • 左右子树均为二叉搜索树
  • 树中没有键值相等的结点

​ 因为性质特殊,所以在查询的时候十分便捷。

二、二叉搜索树常规操作

  • Position Find(TreeNode X,BinarySearchTree BST) 从二叉搜索树中找到节点 X并返回其地址。
  • Position FindMin(BinarySearchTree BST) 从二叉搜索树中找到最小节点 X并返回其地址。
  • Position FindMan(BinarySearchTree BST) 从二叉搜索树中找到最大节点 X并返回其地址。
  • BinarySearchTree Insert(TreeNode X,BinarySearchTree BST) 在二叉搜索树中插入节点 X并返回二叉搜索树。
  • BinarySearchTree Delete(TreeNode X,BinarySearchTree BST) 在二叉搜索树中删除节点 X并返回二叉搜索树。

三、TreeNode 存储结构实现

package org.example.bcbd;

/**
 * @ClassName TreeNode
 * @Description TODO
 * @Author 枫飘长安
 * @Date 2024/4/16 20:49
 * @Version 1.0
 **/

public class TreeNode<T extends Comparable<T>> {

    // 数据域
    private T data;
    // 左子树
    public TreeNode leftChild;
    // 右子树
    public TreeNode rightChild;


    public TreeNode(T data) {
        this(null, data, null);
    }

    public TreeNode(TreeNode leftChild, T data, TreeNode rightChild) {
        this.leftChild = leftChild;
        this.data = data;
        this.rightChild = rightChild;
    }

    public T getData() {
        return data;
    }

    public TreeNode<T> getLeftChild() {
        return leftChild;
    }

    public TreeNode<T> getRightChild() {
        return rightChild;
    }

    public void setData(T data) {
        this.data = data;
    }

    private TreeNode<T> insert(TreeNode<T> node,T value) {
        if (node == null) {
            return  new TreeNode<>(value);
        } else {
            if (compare(node,value) < 0) {
                node.leftChild = insert(node.getLeftChild(),value);
            }else if (compare(node,value) > 0) {
                node.rightChild = insert(node.getRightChild(),value);
            }
            return node;
        }
    }

    private int compare(TreeNode<T> node,T value) {
        return value.compareTo(node.getData());
    }

}

四、二叉搜索树及其常规操作实现

1. 二叉搜索树插入

Tips: 因为其特殊性质,我们很容易用递归实现插入操作

每次插入一个结点,从根节点出发作比较,小的往左子树插,大的往右子树插

    public void insert(T value) {
        if (value == null) {
            return;
        }
        this.root = insert(this.root, value);
    }

    private TreeNode<T> insert(TreeNode<T> node, T value) {
        if (node == null) {
            return new TreeNode<>(value);
        }else {
           if (compare(node, value) < 0) {
               node.leftChild = insert(node.getLeftChild(), value);
           }else if (compare(node,value) > 0) {
               node.rightChild = insert(node.getRightChild(), value);
           }
        }
        return node;
    }

2.二叉搜索树查找

Tips:在一颗二叉搜索树上,最小的值一定在最左边的结点上,最大值一定在最右边的结点上。查找二叉树最值递归实现即可。在查找特定值时注意如果查找的元素不在树中,我们得对其做出异常处理

    public TreeNode<T> find(T value) {
        if (this.root == null) return null;
        return find(this.root, value);
    }

    private TreeNode<T> find(TreeNode<T> node, T value) {
        if (node == null) throw new RuntimeException("the value must not in the tree");

        if (compare(node, value) < 0) {
            return find(node.getLeftChild(), value);
        }else if (compare(node,value) > 0) {
            return find(node.getRightChild(), value);
        }else {
            return node;
        }
    }

	public T findMax() {
        if (this.root == null) return null;
        return findMax(this.root);
    }

    private T findMax(TreeNode<T> node) {
        TreeNode<T> temp = node;
        while (temp.getRightChild() != null) {
            temp = temp.getRightChild();
        }
        return temp.getData();
    }

    public T findMin() {
        if (this.root == null) return null;
        return findMin(this.root);
    }

    private T findMin(TreeNode<T> node) {
        TreeNode<T> temp = node;
        while (temp.getLeftChild() != null) {
            temp = temp.getLeftChild();
        }
        return temp.getData();
    }


3.二叉搜索树删除

Tips: 删除是最难的操作了,因为删掉节点后,整棵树仍然需要为二叉搜索树

  • 叶子结点:直接删除,其父结点指向null
  • 包含一个孩子的结点 :父结点指向要删除结点的自结点(相当于链表中间删除一个元素);
  • 包含左右子树的结点:右子树最小值或左子树最大值替换此结点
    public void delete(T value) {
        if (this.root == null || value == null) return;
        this.root = delete(this.root, value);
    }

    public TreeNode<T> delete(TreeNode<T> node, T value) {

        if (node == null) return null;

        if (compare(node, value) < 0) { // 去删左子树
            node.leftChild = delete(node.getLeftChild(), value);
        }else if (compare(node, value) > 0) { // 去删右子树
            node.rightChild = delete(node.getRightChild(), value);
        }else { // 找到要删除的节点
            if (node.getLeftChild() != null && node.getRightChild() != null) {// 被删除的结点,包含左右子树
                T temp = findMin(node.getRightChild()); // 得到右子树的最小值
                node.setData(temp); //右子树最小值替换当前结点
                node.rightChild = delete(node.getRightChild(), temp); // 从右子树删除这个最小值的结点
            } else {// 被删除的结点,包含一个子树或没有子树
                if (node.getLeftChild() != null) {
                    node = node.getLeftChild();
                } else {
                    node = node.getRightChild();
                }
            }
        }
        return node;
    }

4.二叉搜索树高度

Tips: 就是求树的高度,没什么好讲的。

    public int getTreeHeight() {
        if (this.root == null) return 0;
        return getTreeHeight(this.root);
    }

    private int getTreeHeight(TreeNode<T> node) {
        if (node == null) return 0;

        int leftHeight = getTreeHeight(node.getLeftChild());
        int rightHeight = getTreeHeight(node.getRightChild());

        return Math.max(leftHeight, rightHeight) + 1;
    }

5. 中序遍历打印二叉搜索树

    public void printTree() {
        printTree(this.root);
    }

    private void printTree(TreeNode<T> node) {
        if (node == null) {
            return;
        }
        printTree(node.getLeftChild());
        System.out.print(node.getData() + " ");
        printTree(node.getRightChild());
    }

五、BinarySearchTree完整代码

package org.example.bcbd; // 包名请按照自己的程序设置

/**
 * @ClassName BinarySearchTree
 * @Description TODO
 * @Author 枫飘长安
 * @Date 2024/4/16 20:59
 * @Version 1.0
 **/
public class BinarySearchTree<T extends Comparable<T>> {

    private TreeNode<T> root;


    public BinarySearchTree() {
        this.root = null;
    }

    public BinarySearchTree(TreeNode<T> root) {
        this.root = root;
    }

    public void insert(T value) {
        if (value == null) {
            return;
        }
        this.root = insert(this.root, value);
    }

    private TreeNode<T> insert(TreeNode<T> node, T value) {
        if (node == null) {
            return new TreeNode<>(value);
        }else {
           if (compare(node, value) < 0) {
               node.leftChild = insert(node.getLeftChild(), value);
           }else if (compare(node,value) > 0) {
               node.rightChild = insert(node.getRightChild(), value);
           }
        }
        return node;
    }

    private int compare(TreeNode<T> node, T value) {
        return value.compareTo(node.getData());
    }

    public void printTree() {
        printTree(this.root);
    }

    private void printTree(TreeNode<T> node) {
        if (node == null) {
            return;
        }
        printTree(node.getLeftChild());
        System.out.print(node.getData() + " ");
        printTree(node.getRightChild());
    }

    public T findMax() {
        if (this.root == null) return null;
        return findMax(this.root);
    }

    private T findMax(TreeNode<T> node) {
        TreeNode<T> temp = node;
        while (temp.getRightChild() != null) {
            temp = temp.getRightChild();
        }
        return temp.getData();
    }

    public T findMin() {
        if (this.root == null) return null;
        return findMin(this.root);
    }

    private T findMin(TreeNode<T> node) {
        TreeNode<T> temp = node;
        while (temp.getLeftChild() != null) {
            temp = temp.getLeftChild();
        }
        return temp.getData();
    }

    public TreeNode<T> find(T value) {
        if (this.root == null) return null;
        return find(this.root, value);
    }

    private TreeNode<T> find(TreeNode<T> node, T value) {
        if (node == null) throw new RuntimeException("the value must not in the tree");

        if (compare(node, value) < 0) {
            return find(node.getLeftChild(), value);
        }else if (compare(node,value) > 0) {
            return find(node.getRightChild(), value);
        }else {
            return node;
        }
    }

    public int getTreeHeight() {
        if (this.root == null) return 0;
        return getTreeHeight(this.root);
    }

    private int getTreeHeight(TreeNode<T> node) {
        if (node == null) return 0;

        int leftHeight = getTreeHeight(node.getLeftChild());
        int rightHeight = getTreeHeight(node.getRightChild());

        return Math.max(leftHeight, rightHeight) + 1;
    }

    public void delete(T value) {
        if (this.root == null || value == null) return;
        this.root = delete(this.root, value);
    }

    public TreeNode<T> delete(TreeNode<T> node, T value) {

        if (node == null) return null;

        if (compare(node, value) < 0) { // 去删左子树
            node.leftChild = delete(node.getLeftChild(), value);
        }else if (compare(node, value) > 0) { // 去删右子树
            node.rightChild = delete(node.getRightChild(), value);
        }else { // 找到要删除的节点
            if (node.getLeftChild() != null && node.getRightChild() != null) {// 被删除的结点,包含左右子树
                T temp = findMin(node.getRightChild()); // 得到右子树的最小值
                node.setData(temp); //右子树最小值替换当前结点
                node.rightChild = delete(node.getRightChild(), temp); // 从右子树删除这个最小值的结点
            } else {// 被删除的结点,包含一个子树或没有子树
                if (node.getLeftChild() != null) {
                    node = node.getLeftChild();
                } else {
                    node = node.getRightChild();
                }
            }
        }
        return node;
    }
}

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值