Java二叉查找树最简单实现

什么是二叉树

简单来说,二叉树首先是一棵树,然后有以下条件

  • 每个节点最多有2个孩子节点

  • 二叉树有

    • 一个根节点
    • 一个左子树(可能为空)
    • 一个右子树(可能为空)

特例

  • 完全二叉树
    叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
    《Java二叉查找树最简单实现》

  • 满二叉树
    一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树
    《Java二叉查找树最简单实现》

二叉查找树

每个节点有一个键,每个节点的键
* 比它的左子树要大
* 比它的右子树要小

实现

一个Node包含四个元素:

  • key和value
  • 左子树和右子树的引用

get

类似binary search。

 public V get(K key){
        Node x = root;
        while (x!=null){
            int cmp = key.compareTo(x.key);

            if(cmp <0 ) x = x.left;
            else if(cmp > 0) x = x.right;
            else return x.value;
        }
        return null;
    }

put

首先也是对key进行get操作,然后分两种情况:

  • key在树里=>重置value
  • key不在树里=>增加新节点
    public void put(K key,V value){
        root = put(root,key,value);
    }

    private Node put(Node x,K key,V value){
        if( x == null) return new Node(key,value);
        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;
        return x;
    }

Floor&ceiling

  • Floor 小于等于给定Key的最大的key
  • Ceiling 大于等于给定Key的最小的key

计算floor

有三种情况

  • k等于root
    返回k
  • k小于root
    floor(k)在左子树
  • k大于root
    floor(k)在右子树:
    如果有任何key<=k : 返回key
    否则返回root
   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;
        return x;
    }

minimum&maximum

《Java二叉查找树最简单实现》

  • min: 最左边非空节点
  • max: 最右边非空节点
   public Key min(){
        return min(root).key;
    }

    private Node min(Node x){
        //如果x的左子树为空,那么key最小的节点就是x;否则最小的节点就是左子树的最小节点
        if(x.left == null) return x;
        return min(x.left);
    }

删除最小的节点

  • 一直向左直到找到一个节点的左子树为空
  • 让它的右子树替换该节点
  • 更新子树的数量

《Java二叉查找树最简单实现》

 public void deleteMin(){
        root = deleteMin(root);
    }

    private Node deleteMin(Node x){
        //找到没有左子树的节点,将它的右子树替代它
        if(x.left == null)  return x.right;
        //删除之后,为parent设置合适的链路
        x.left = deleteMin(x.left);//因为x.left可能指向了x.left.right
        //更新节点的数量
        x.N = size(x.left) + size(x.right) + 1;
        return x;
    }

删除节点

删除key为k的节点:首先查询含有k的节点t。如果找到了,那么分3种情况:

  • 无孩子节点
    将t设为null即可
  • 有一个孩子节点
    将t的父节点的指向t的孩子节点即可
    《Java二叉查找树最简单实现》
  • 有两个孩子节点

    • 找到t的后继者x(t的右子树中最小的节点)
    • 删除x所在的节点
    • 将x替换到t的位置
    • > 满足BST的定义
  • 《Java二叉查找树最简单实现》

   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;//t临时指向x
            x = min(t.right);//x的后继者
            //x的后继者替换x的位置
            x.right = deleteMin(t.right);
            x.left = t.left;
        }

        x.N = 1 + size(x.left) + size(x.right);
        return x;
    }

## 完整代码

 package com.algorithms.tree;

/** * Create by yinjingwei on 2018/2/20/020. */
public class BST<Key extends Comparable<Key>,Value> {
    private Node root;//BST树的根节点

    private class Node{
        private Key key;
        private Value value;
        private Node left,right;
        private int N; //nodes in subtree rooted here
        public Node(Key key,Value value,int N){
            this.key = key;
            this.value = value;
            this.N = N;
        }
    }

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

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

    public Value get(Key key){
        return get(root,key);
    }

    private Value get(Node x, Key key){
        //从x节点往下查找Key为key的节点,未找到返回null
        if(x != 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;
        }
        return null;
    }

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

    private Node put(Node x, Key key, Value val){
        //如果找到了key,则改变相应节点的值;否则插入
        if(x == null) return new Node(key,val,1);
        int cmp = key.compareTo(x.key);
        if( cmp <0 ) x.left = put(x.left,key,val);
        else if(cmp >0) x.right = put(x.right,key,val);
        else x.value = val;
        x.N = size(x.left) + size(x.right) + 1;//会往上递归调用回去
        return x;
    }

    public Key min(){
        return min(root).key;
    }

    private Node min(Node x){
        //如果x的左子树为空,那么key最小的节点就是x;否则最小的节点就是左子树的最小节点
        if(x.left == null) return x;
        return min(x.left);
    }

    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 x;
        else return t;
    }


    public void deleteMin(){
        root = deleteMin(root);
    }

    private Node deleteMin(Node x){
        //找到没有左子树的节点,将它的右子树替代它
        if(x.left == null)  return x.right;
        //删除之后,为parent设置合适的链路
        x.left = deleteMin(x.left);//因为x.left可能指向了x.left.right
        //更新节点的数量
        x.N = size(x.left) + size(x.right) + 1;
        return x;
    }

    public void delete(Key key){
        root = delete(root,key);
    }

    /** * 删除key为k的节点:首先查询含有k的节点t。如果找到了,那么分3种情况: * 无孩子节点 * 将t设为null即可 * 有一个孩子节点 * 将t的父节点的指向t的孩子节点即可 * 有两个孩子节点 * 找到t的后继者x(t的右子树中最小的节点) * 删除x所在的节点 * 将x替换到t的位置 * @param x * @param key * @return */
    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;//t临时指向x
            x = min(t.right);//x的后继者
            //x的后继者替换x的位置
            x.right = deleteMin(t.right);
            x.left = t.left;
        }

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



    }

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

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





}
    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/yjw123456/article/details/79917250
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞