java 二分搜索树(又二叉搜索树、二叉查找树等)节点的插入、查询、删除

一、概念及其介绍

二分搜索树(英语:Binary Search Tree),也称为 二叉查找树 、二叉搜索树 、有序二叉树或排序二叉树。满足以下几个条件:

  • 若它的左子树不为空,左子树上所有节点的值都小于它的根节点。
  • 若它的右子树不为空,右子树上所有的节点的值都大于它的根节点。

它的左、右子树也都是二分搜索树。

二、适用说明

二分搜索树有着高效的插入、删除、查询操作。

平均时间的时间复杂度为 O(log n),最差情况为 O(n)。二分搜索树与堆不同,不一定是完全二叉树,底层不容易直接用数组表示故采用链表来实现二分搜索树。

查找元素插入元素删除元素
普通数组O(n)O(n)O(n)
顺序数组O(logn)O(n)O(n)
二分搜索树O(logn)O(logn)O(logn)

三、Java代码实现增删查

public class BinarySearchTree <Key extends Comparable<Key>,Value>{

    // 树中的节点为私有的类, 外部不需要了解二分搜索树节点的具体实现
    private class TreeNode{
        public Key key;
        public Value value;
        public TreeNode left,right;

        public TreeNode(Key key,Value value){
            this.key=key;
            this.value=value;
            this.left=null;
            this.right=null;
        }
    }

    private TreeNode root;//根节点
    private int treeSize;//树节点总数

    // 构造函数, 默认构造一棵空二分搜索树
    public BinarySearchTree() {
        root=null;
        treeSize=0;
    }

    public void insert(Key key,Value value){
        //初次插入节点,根节点为空
        if (root==null){
            root=new TreeNode(key,value);
            treeSize++;
        }else {
            this.add(root,key,value);
        }
    }

    //插入一个节点
    // 向以node为根的二分搜索树中, 插入节点(key, value), 使用递归算法
    // 返回插入新节点后的二分搜索树的根
    private TreeNode add(TreeNode node,Key key,Value value){
        if (node==null){
            node=new TreeNode(key,value);
            treeSize++;
            return node;
        }
        if (key.compareTo(node.key)==0){
            node.value=value;
        }else if (key.compareTo(node.key)<0){
            //如果node.left或node.right为空,则会在下轮递归被第一个if处理,所以此处
            //不需判断node.left或node.right为空,即null也视为二分搜索树
            node.left=add(node.left,key,value);
        }else {
            node.right=add(node.right,key,value);
        }
        return node;
    }

    //节点查找--是否包含该节点
//    二分搜索树没有下标, 所以针对二分搜索树的查找操作, 这里定义一个 contain 方法, 判断二分搜索树是否包含某个元素,
//    返回一个布尔型变量, 这个查找的操作一样是一个递归的过程,
    private boolean contain(TreeNode node,Key key){
        if (node==null){
            return false;
        }
        if (key.compareTo(node.key)==0){
            return true;
        }else if(key.compareTo(node.key)<0){
            return contain(node.left,key);
        }else {
            return contain(node.right,key);
        }
    }
    //节点查找--获取节点值
    private Value select(TreeNode node,Key key){
        if (node==null){
            return null;
        }
        if (key.compareTo(node.key)==0){
            return node.value;
        }else if(key.compareTo(node.key)<0){
            return select(node.left,key);
        }else {
            return select(node.right,key);
        }
    }

    //二分搜索树遍历分为两大类,深度优先遍历和层序遍历。
//深度优先遍历分为三种:先序遍历(preorder tree walk)、中序遍历(inorder tree walk)、后序遍历(postorder tree walk),分别为:
//1、前序遍历:先访问当前节点,再依次递归访问左右子树。
//2、中序遍历:先递归访问左子树,再访问自身,再递归访问右子树。
//3、后序遍历:先递归访问左右子树,再访问自身节点。

    //前序遍历
    private void preOrder(TreeNode node){
        if (node!=null){
            System.out.print( node.value+" ");
            preOrder(node.left);
            preOrder(node.right);
        }
    }
    //中序遍历
    private void inOrder(TreeNode node){
        if (node!=null){
            inOrder(node.left);
            System.out.print(node.value+" ");
            inOrder(node.right);
        }
    }
    //后序遍历
    private void postOrder(TreeNode node){
        if (node!=null){
            postOrder(node.left);
            postOrder(node.right);
            System.out.print(node.value+" ");
        }
    }

    //层序遍历:二分搜索树的层序遍历,即逐层进行遍历,即将每层的节点存在队列当中,
    // 然后进行出队(取出节点)和入队(存入下一层的节点)的操作,以此达到遍历的目的。
    private void levelOrder(TreeNode root){
        if(root!=null){
            // 我们使用LinkedList来作为我们的队列
            LinkedList<TreeNode> queue = new LinkedList<>();
            queue.add(root);
            while (!queue.isEmpty()){
                TreeNode treeNode = queue.removeFirst();
                System.out.print(" " + treeNode.value);
                if (treeNode.left!=null){
                    queue.add(treeNode.left);
                }
                if (treeNode.right!=null){
                    queue.add(treeNode.right);
                }
            }
        }

    }
    // 查找以node为根的二分搜索树的最小键值所在的节点:在node左子树中递归找到不存左子树的节点
    //该节点则为最小,最大值与此类似
    private TreeNode minNode(TreeNode treeNode){
        if (treeNode.left==null){
            return treeNode;
        }
        return minNode(treeNode.left);
    }
    //找最大值
    private TreeNode maxNode(TreeNode treeNode){
        if (treeNode.right==null){
            return treeNode;
        }
        return minNode(treeNode.right);
    }

    // 删除掉以node为根的二分搜索树中键值为key的节点, 递归算法
    // 返回删除节点后新的二分搜索树的根
    private TreeNode removeNode(TreeNode node,Key key){
        //删除操作的基础是查找
        if (node==null){
            return null;
        }
        if (key.compareTo(node.key)<0){
            node.left=removeNode(node.left,key);
            return node;
        } else if (key.compareTo(node.key)>0){
            node.right=removeNode(node.right,key);
            return node;
        } else {//key==node.key
            //如果目标节点的左子树为空,只有右子树,则让右子树节点代替目标节点,整个搜索树性质不变
            if (node.left==null){
                node=node.right;
                treeSize--;
                return node;
            }else if (node.right==null){
                //如果目标节点的右子树为空,只有左子树,则让左子树节点代替目标节点,整个搜索树性质不变
                node=node.left;
                treeSize--;
                return node;
            }else {//左右子树都有:找到右子树中最小的节点替代目标节点
                TreeNode minNode = minNode(node.right);
                //然后删除右子树最小节点
                node.right=removeNode(node.right,minNode.key);
                node.key= minNode.key;
                node.value= minNode.value;
                return node;
            }
        }
    }
    public static void main(String[] args) {
        BinarySearchTree searchTree = new BinarySearchTree();
        Integer[] arr=new Integer[]{41,22,58,15,33,50,60,13,37,42,53,59,63};
        for (Integer  integer:arr ) {
            System.out.println("插入数据"+integer );
            searchTree.insert(integer,integer);
        }
       /* System.out.println("searchTree = " + searchTree.root.value);
        System.out.println("isContain = " + searchTree.contain(searchTree.root, 62));
        System.out.println("select = " + searchTree.select(searchTree.root, 13));

        searchTree.preOrder(searchTree.root);
        System.out.println(" ");
        searchTree.inOrder(searchTree.root);
        System.out.println(" ");
        searchTree.postOrder(searchTree.root);
        System.out.println(" ");*/
        System.out.println("数据插入完成");
        searchTree.levelOrder(searchTree.root);

        System.out.println("\n"+"删除");
        searchTree.removeNode(searchTree.root, 60);
        searchTree.levelOrder(searchTree.root);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值