数据结构——二分搜索树

二分搜索树

二分搜索树的本质是树,对于树的基本知识,我在我的一片关于的博文的开头做了讲述,大家可以参考。这里将重点讲述树的递归结构。

定义

二分搜索树是一颗二叉树, 二分搜索树每个节点的左子树的值都小于该节点的值,每个节点右子树的值都大于该节点的值,其任意一个节点的每棵子树都满足二分搜索树的定义。NULL节点和只有一个节点的树也是二叉树

理解

通过上面对二叉树的定义,我们知道了向树中存储的元素必须具有可比较性,我们在写代码的时候。向树中存储的是一个泛型为E的元素,为了实现他的可比较性,所以要让他继承自Comparable接口。
在这里简单说一下Comparable接口,他下面只有CompareTo一个方法,这个方法是用于比较字符串顺序的,根据字典顺序进行排序。所有想要具有比较功能的类,都建议实现这个接口,而非是自己定义这个功能,这是面向对象的概念(将具有相同功能的事物抽象到一个共同的类或接口),并且为了多态也建议通过实现接口来进行向上转型,通过接口来操作具体实现,这也是面向接口编程要求我们做的。
好,我们言归正传,继续讲解二分搜索树,我这样的话就可以写出二分搜索树的底层定义了

private class Node{
        public E e;
        public Node left, right;
        public Node (E e){
            this.e = e;
            left = null;
            right = null;
        }
    }

将这个类设置为私有的内部类,用户不需要直接访问他,当我们在向其中插入元素e的时候,需要判断他的根节点是否为空,若为空的话,直接将其赋值给根节点root = new Node(e) ,否则的话,进入递归循环,在这里需要判断递归的终止条件就是把元素e放入到了树中,循环条件呢?循环条件是看e的值比当前节点的值大还是小,大的话放入其右子树,小的话放入其左子树,这里分别调用的是add(node.right, e);add(node.left, e);,这个add方法调用的就是自己本身。

public void add(E e){
        if (root == null){
            root = new Node(e);
            size ++;
        }else{
            add(root,e);
        }
    }
    //递归插入元素e
    public void add(Node node, E e){
        //递归终止的条件
        if (e.equals(node.e)){
            return;
        }else if (e.compareTo(node.e) < 0 && node.left == null ){
            node.left = new Node(e);
            size ++;
            return;
        }else if (e.compareTo(node.e) > 0 && node.right == null){
            node.right = new Node(e);
            size ++;
            return;
        }
        if (e.compareTo(node.e) < 0){
            add(node.left, e);
        }else {
            add(node.right, e);
        }
    }

在上面的代码中,我们发现在头节点的时候判断了他是否为空,在后面的递归中,也判断了插入的位置的节点是否为空,这样双重的判断很恼火,所以我们优化一下插入,对要插入的值直接调用add(root,e),此时它的返回值为root也就是返回插入新节点二分搜索树的根
所以优化后算法的思路就是,当用户插入节点e时,先在根节点判断是否为空,是的话就插入,返回一个Node对象,将其赋值给root,如果不为空的话,就就和当前的节点比较,如果小的话,就在当前节点的左子树中添加e,如果node.left为空,那么就将当前的node.left赋值为e,因为它会重新调用本身,在第一个if循环返回了root。将其赋给了node.left。关键是记住node是一个可变的。

public void add(E e) {
        root = add(root,e);
    }

    //返回插入新节后二分搜索树的根
    public Node add(Node node, E e) {
        //递归终止的条件
        if (node == null) {
            size++;
            return new Node(e);
        }
        if (e.compareTo(node.e) < 0) {
            node.left = add(node.left, e);
        } else if (e.compareTo(node.e) > 0){
            node.right = add(node.right, e);
        }
        return node;
    }

查找

通过对向树中插入数据的理解,我们可以很简单的写出在树中搜索元素的代码

   public boolean contains (E e){
        return  contains(root, e);
    }
    private boolean contains(Node node, E e){
        if (node == null){
            return false;
        }
        if (e.compareTo(node.e) == 0) {
            return true;
            //要查找的值比当前节点的值小则和他的左子树比较
        }else if (e.compareTo(node.e) < 0){
            return contains(node.left,e);
        }else {
            return contains(node.right,e);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值