Java实现 二叉查找树BST(递归版)

二叉查找树 BST (递归版)


参考 算法(第四版)

重点

  1. 每个节点的键都大于其左子树中任意节点的键而小于其右子树中任意节点的键。

  2. 对于二叉树中任意节点x总是有:

    size(x) = size(x.left) + size(x.right) + 1;

  3. (下文)root私有化,所以通过调用公共方法间接调用私有方法。

模板

public class BST<Key extends Comparable<Key>, Value> {
    private Node root;

    private class Node{
        private Key key; // 键
        private Value val; // 值
        private Node left, right;
        private int N; // 节点数

        public Node(Key key, Value val, int n) {
            this.key = key;
            this.val = val;
            N = n;
        }
    }
}

(子)树总节点数

public int size(){
        return size(root);
    }

    private int size(Node x){
        if (x == null) return 0;
        else return x.N;
    }

查找

public Value get(Key key){ // 查找(每次都定义了树的一条路径)
        return get(root, key);
    }

    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.val;
    }

插入

public void put(Key key, Value val){ // 插入
        root = put(root, key ,val);
    }

    private Node put(Node x, Key key, Value val){
        if (x == null) return new Node(key, val ,1); // new

        int cmp = key.compareTo(x.key);
        if (cmp < 0) x.left = put(x.left, key, val); // insert
        else if (cmp > 0) x.right = put(x.right, key, val);
        else x.val = val; // update
        x.N = size(x.left) + size(x.right) + 1;
        return x;
    }

键的最值

public Key min(){ // 左下角最小键值
        return min(root).key;
    }

    private Node min(Node x){
        if (x.left == null) return x;
        return min(x.left);
    }

    public Key max(){ // 右下角最大键值
        return max(root).key;
    }

    private Node max(Node x){
        if (x.right == null) return x;
        return max(x.right);
    }

键的邻值

public Key floor(Key key){
        Node x =floor(root, key); // 找到对应节点
        if (x == null) return null;
        return x.key;
    }

    private Node floor(Node x, Key key){ // 含 地板键(升序最近) 的节点
        if (x == null) return null;

        int cmp = key.compareTo(x.key);
        if (cmp == 0) return x;
        if (cmp < 0) return floor(x.left, key); // 左子树找
        Node t = floor(x.right, key); // 右子树找
        if (t != null) return t;
        else return x;

    }

    public Key ceil(Key key){
        Node x =ceil(root, key); // 找到对应节点
        if (x == null) return null;
        return x.key;
    }

    private Node ceil(Node x, Key key){ // 含 天花板键(降序最近) 的节点
        if (x == null) return null;

        int cmp = key.compareTo(x.key);
        if (cmp == 0) return x;
        if (cmp > 0) return floor(x.right, key); // 右子树找
        Node t = floor(x.left, key); // 左子树找
        if (t != null) return t;
        else return x;
    }

(键的)排名 <–> 键值

public Key select(int k){ // 排名 -> 键值
        return select(root, k).key;
    }

    private Node select(Node x, int k){
        if (x == null) return null;

        int t = size(x.left);
        if (t > k) return select(x.left, k);
        else if (t < k) return select(x.right, k - t - 1);
        else return x;
    }

    public int rank(Key key){ // 键值 -> 排名
        return rank(key, root);
    }

    private int rank(Key key, Node x){
        if (x == null) return 0;

        int cmp = key.compareTo(x.key);
        if (cmp < 0) return rank(key, x.left);
        else if (cmp > 0) return size(x.left) + 1 + size(x.right);
        else return size(x.left);
    }

利用好size()

删除节点

public void deleteMin(){
        root = deleteMin(root); // 替换根节点,并更新该子树(其所有节点的键值都大于 x.key )
    }

    private Node deleteMin(Node x){
        if (x.left == null) return x.right; // 该根节点最小

        x.left = deleteMin(x.left);  // 自下而上更新 链接,节点计数器
        x.N = size(x.left) + size(x.right) + 1;
        return x;
    }

    public void delete(Key key){
        root = delete(root, key); // 更新被删除节点的位置
    }

    private Node delete(Node x, Key key){
        if (x == null) return null;

        int cmp = key.compareTo(x.key);
        if (cmp < 0) x.left = delete(x.left, key);
        else if (cmp > 0) x.right = delete(x.right, key);
        else {
            if (x.right == null) return x.left;
            if (x.left == null) return x.right;

            Node t = x; // 左右子树都不为空
            x = min(t.right); // 后继节点(其右子树中键值最小的节点)
            x.right = deleteMin(t.right);
            x.left = t.left;
        }

        x.N = size(x.left) + size(x.right) + 1; // 更新节点计数器
        return x;
    }

请添加图片描述

遍历

public void print(){
        print(root);
    }

    private void print(Node x){ // middle
        if (x == null) return;
        print(x.left);
        System.out.println(x.key);
        print(x.right);
    }

    public Iterable<Key> keys(){ // BST范围查找
        return keys(min(), max());
    }

    public Iterable<Key> keys(Key lo, Key hi){
        ArrayList<Key> list = new ArrayList<>();
        keys(root, list, lo, hi);
        return list;
    }

    private void keys(Node x, ArrayList<Key> list, Key lo, Key hi) {
        if (x == null) return;

        int cmplo = lo.compareTo(x.key); // 类比 二分查找 + 中序遍历
        int cmphi = hi.compareTo(x.key);
        if (cmplo < 0) keys(x.left, list, lo, hi);
        if (cmplo <= 0 && cmphi >= 0) list.add(x.key); // 加入list
        if (cmphi > 0) keys(x.right, list, lo, hi);
    }

keys()的返回数据类型支持foreach迭代即可。

测试

public static void main(String[] args) {
        BST<String,Integer> bst = new BST<>();
        bst.put("D",4);
        bst.put("E",5);
        bst.put("F",6);
        bst.put("G",7);
        bst.put("A",1);
        bst.put("B",2);
        bst.put("C",3);


        Iterable<String> k = bst.keys();

        for (String s : k) {
            System.out.println(s + " -> "+ bst.get(s));
        }


    }  

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值