【树结构】二叉搜索树

本文详细介绍了二叉搜索树(BST)的定义、性质、优点和缺点,以及Java实现的详细过程,包括节点定义、计算树的大小、查找、插入、最大最小键值、键值取整、排名、删除操作等。同时,文章还提及了BST的最坏情况和优化方案——平衡树。
摘要由CSDN通过智能技术生成

二叉搜索树定义

先来说说这个二叉排序树的定义和性质:

定义:二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的键值均小于或等于它的根结点的键值;
(2)若右子树不空,则右子树上所有结点的键值均大于或等于它的根结点的键值;
(3)左、右子树也分别为二叉排序树;
(4)节点的Key唯一

二叉搜索树BST的优点以及缺点

根据BST的定义和中序遍历(左根右节点遍历顺序)可得出,对于二叉搜索树的中序遍历可以使得节点有序。

BST的优点对于dictionary来说,主要优点就是使得查找速度大大提升,不用再进行遍历操作。时间复杂度一般情况下是O(logn),但是最坏的情况下会出现“链表”的形式,复杂度退化到O(N),比如下所示

11
 \
  13
   \
    15
     \
      17

当然也有基于BST优化出的各种平衡树,来保证时间复杂度O(logn)的稳定性。

二叉搜索树的Java实现

下面的代码将用java实现,并且全部基于递归实现(非递归算法复杂一些且效率高)。主要讨论BST的如下操作:
查找、插入、最大键、最小键、向上取整、向下取整、排名k的键、获取键key的排名、删除最大最小键、删除操作、范围查找。

1.结点的数据结构的定义

下面是BST(后文都用BST表示二叉排序树)中结点的数据结构的定义。

private class Node{
   
    private Key key;//键
    private Value value;//值
    private Node left, right;//指向子树的链接:包括左子树和右子树.
    private int N;//以当前节点为根的子树的结点总数
//构造器
    public Node(Key key, Value value, int N) {
   
        this.key = key;
        this.value = value;
        this.N = N;
    }
}

此外,对于整个二叉查找树来说,有一个根节点,所以在BST类中定义了一个根结点:

private Node root;//二叉查找树的根节点

2. 计算二叉排序树的size

思想: 根据我们数据结构Node中的定义,里面有一个属性 N 表示的就是以当前节点为根的子树的结点总数。所以源码如下:

/**
 * 获取整个二叉查找树的大小
 * @return
 */
public int size(){
   
    return size(root);
}
/**
 * 获取某一个结点为根结点的二叉查找树的大小
 * @param x
 * @return
 */
private int size(Node x){
   
    if(x == null){
   
        return 0;
    } else {
   
        return x.N;
    }
}

3. 查找和插入

在实现BST类的时候,BST继承自Comparable接口的,实现compareTo()函数。因为我们知道二叉查找树的键值是有有序的,左子树小于根节点,右子树大于根节点。所以实现Comparable接口,那么我们就很容易根据key找到插入的位置,而且对于BTS来说,插入的位置都是在叶子节点处。对于插入和查找都是基于键值的比较。下面是源码:

/**
 * 查找:通过key获取value
 * @param key
 * @return
 */
public Value get(Key key){
   
    return get(root, key);
}
/**
 * 在以 x 为根节点的子树中查找并返回Key所对应的值,如果找不到就返回null
 * 递归实现
 * @param x
 * @param key
 * @return
 */
private Value get(Node x, Key key){
   
    if(x == null){
   
        return null;
    }
	//键值的比较
    int cmp = key.compareTo(x.key);
    if(cmp<0){
   
        return get(x.left, key);
    }else if(cmp>0){
   
        return get(x.right, key);
    } else{
   
        return x.value;
    }
}


/**
 * 插入:设置键值对
 * @param key
 * @param value
 */
public void put(Key key, Value value){
   
    root = put(root, key, value);
}
/**
 * key如果存在以 x 为根节点的子树中,则更新它的值;
 * 否则将key与value键值对插入并创建一个新的结点.
 * @param x
 * @param key
 * @param value
 * @return
 */
private Node put(Node x, Key key, Value value){
   
    if( x==null ){
   
        x = new Node(key, value, 1);
        return x;
    }
    int cmp = key.compareTo(x.key);
    if(cmp<0){
   
        x.left = put(x.left, key, value);
    }else if(cmp>0){
   
        x.right = put(x.right, key, value);
    } else{
   
        x.value=value;//更新value的值
    }
    //设置根节点的N属性
    x.N = size(x.left) + size(x.right) + 1;

    return x;
}

4. 最大键和最小键的实现

求BST中的最大键值和最小键值。根据BSt的特性,其实原理很简单:最小值就是最左下边的一个节点。最大键值就是最右下边的结点。源码如下:

/**
 * 最小键
 */
public Key min(){
   
    return min(root).key;
}
/**
 * 返回结点x为root的二叉排序树中最小key值的Node
 * @param x
 * @return 返回树的最小key的结点
 */
private Node min(Node x){
   
    if(x.left == null){
   
        return x;
    }else{
   
        return min(x.left);
    }
}

/**
 * 最大键
 */
public Key max(){
   
    return max(root).key;
}
/**
 * 返回结点x为root的二叉排序树中最大key值的Node
 * @param x
 * @return
 */
private Node max(Node x){
   
    if(x.right == null){
   //右子树为空,则根节点是最大的
        return x;
    }else{
   
        return max(x.right);
    }
}

5. Key值向下取整和向上取整

所谓的向下取整和向上取整,就是给定键值key,向下取整的意思就是找出小于等于当前key的的Key值。向上取整的意思就是找出大于等于当前key的的Key值。实现也是基于Comparable接口的,具体的源码如下:

/**
 * key向下取整
 */
public Key floor(Key key){
   
    Node x = floor(root, key);
    if(x == null){
   
        return null;
    }
    return x.key;
}
/**
 * 以x 为根节点的二叉排序树,查找以参数key的向下取整的Node
 * @param x
 * @param key
 * @return
 */
private Node floor(Node x
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值