美文网首页
二叉查找树

二叉查找树

作者: 囧囧有神2号 | 来源:发表于2017-09-03 14:01 被阅读0次

定义:一个二叉查找树是一棵二叉树,其中每个节点都含有一个Comparable键(以及相关联的值),且每个节点中的键都大于其左子树中的任意节点的键,而小于右子树任意节点的键。
下面是完整的代码:

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

    public BinarySearchTree() {
    }
    
    private class Node {
        private Key key;
        private Value value;
        private Node left;
        private Node right;
        private int size;   //以该节点为根的字树中的节点总数(包括自身)
        
        public Node(Key key, Value value, int size) {
            this.key = key;
            this.value = value;
            this.size = size;
        }
    }
    public void put(Key key, Value value) {
        if (key == null) throw new IllegalArgumentException("called put() with a null key");
        if (value == null) {   //插入一个value为null的值代表要删除他
            delete(key);
            return;
        }
        root = put(root, key, value);
    }

    //递归在左右子树中查找直到找到合适位置插入,注意size值,从上往下递归再从下往上返回时重塑
size值
    private Node put(Node node, Key key, Value value) {
        if (node == null) return new Node(key, value, 1);
        
        int cmp = key.compareTo(node.key);
        if (cmp < 0)        node.left = put(node.left, key, value);
        else if (cmp > 0)   node.right = put(node.right, key, value);
        else                node.value = value;
        
        node.size = size(node.left) + size(node.right) + 1;
        return node;
    }
    
    public Value get(Key key) {
        return get(root, key);
    }
    
    private Value get(Node node, Key key) {
        if (node == null) return null;
        int cmp = key.compareTo(node.key);
        if (cmp < 0)        return get(node.left, key);
        else if (cmp > 0)   return get(node.right, key);
        else                return node.value;
    }

    //删除key键
    public void delete(Key key) {
        if (key == null) throw new IllegalArgumentException("called delete() with a null key");
        root = delete(root, key);
    }
    
    private Node delete(Node node, Key key) {
        if (node == null) return null;    //key不存在
        
        int cmp = key.compareTo(node.key);
        if (cmp < 0) node.left = delete(node.left, key);
        else if (cmp > 0) node.right = delete(node.right, key);
        else {
            if (node.left == null) return node.right;  //左子树为空直接返回右子树
            if (node.right == null) return node.left;
            //左右子树都在的情况下,找到右子树中的最小节点,用它来代替被删除节点
            Node temp = node;
            node = min(node.right);
            node.right = deleteMin(temp.right);
            node.left = temp.left;
        }
        node.size = size(node.left) + size(node.right) + 1;  //一个节点大小=左子树大小+右子树大小+1
        return node;
    }

    //删除最大键
    public void deleteMax() {
        if (isEmpty()) throw new NoSuchElementException("called deleteMax() with empty symbol table");
        root = deleteMax(root);
    }
    
    private Node deleteMax(Node node) {
        if (node.right == null) return node.left;
        node.right = deleteMax(node.right);
        node.size = size(node.right) + size(node.left) + 1;
        return node;
    }

    //删除最小键
    public void deleteMin() {
        if (isEmpty()) throw new NoSuchElementException("called deleteMin() with empty symbol table");
        root = deleteMax(root);
    }
    
    private Node deleteMin(Node node) {
        if (node.left == null) return node.right;
        node.left = deleteMin(node.left);
        node.size = size(node.left) + size(node.right) + 1;
        return node;
    }
    
    public int size() {
        return size(root);
    }
    
    private int size(Node node) {
        if (node == null)   return 0;
        else                return node.size;
    }
    
    private boolean isEmpty() {
        return size() == 0;
    }
    
    public Key min() {
        if (isEmpty()) throw new NoSuchElementException("called min() with empty symbol table");
        return min(root).key;
    }

    private Node min(Node node) {
        if (node.left == null)  return node;
        else                    return min(node.left);
    }
    
    public Key max() {
        if (isEmpty()) throw new NoSuchElementException("called max() with empty symbol table");
        return max(root).key;
    }
    
    private Node max(Node node) {
        if (node.right == null) return node;
        else                    return max(node.right);
    }
    
    /**
     * 二叉树中小于等于key的最大key键
     * @param key
     * @return
     */
    public Key floor(Key key) {
        if (key == null) throw new IllegalArgumentException("called floor() with a null key");
        if (isEmpty()) throw new NoSuchElementException("called floor() with empty symbol table");
        Node result = floor(root, key);
        if (result == null) return null;
        else                return result.key;
    }
    //递归直到找到key返回,若没有相匹配的则返回最后一个比key小的node,即最后一个调用floor(node.right,key)的node。
原因如下:往左递归寻找是因为要找到一个小于key的node,往右找是因为找到了已经找到了一个小于key的node,
要往右找找有没有更接近key的node,所以最后一个调用floor(node.right,key)的node就是我们想要的值
    private Node floor(Node node, Key key) {
        if (node == null) return null;   //表示树中没有与key相等的值
        int cmp = key.compareTo(node.key);
        if (cmp == 0) return node;   //表示找到了与key相等的值
        if (cmp < 0) return floor(node.left, key);
        Node temp = floor(node.right, key);
        if (temp != null) return temp;
        else              return node;
    }
    
    /**
     * 大于等于key的最小key键
     * @param key
     * @return
     */
    public Key ceiling(Key key) {
        if (key == null) throw new IllegalArgumentException("called ceiling() with a null key");
        if (isEmpty()) throw new NoSuchElementException("called ceiling() with empty symbol table");
        Node result = ceiling(root, key);
        if (result == null) return null;
        else return result.key;
    }
    
    private Node ceiling(Node x, Key key) {
        if (x == null) return null;
        int cmp = key.compareTo(x.key);
        if (cmp == 0) return x;
        if (cmp > 0) return ceiling(x.right, key);
        Node temp = ceiling(x.left, key);
        if (temp != null) return temp;
        else return x;
    }
    
    /**
     * 返回的这个键在树中正好有k个小于它的键
     * @param k
     * @return
     */
    public Key select(int k) {
        if (k < 0 || k >= size()) 
            throw new IllegalArgumentException("called select() with wrong number : " + k);
        Node result = select(root, k);
        return result.key;
    }
    
    private Node select(Node x, int k) {
        int size = size(x.left);
        if (k < size) return select(x.left, k);
        else if (k > size) return select(x.right, k-size-1);
        else return x;
    }
    //返回二叉树中小于key的node的个数
    public int rank(Key key) {
        if (key == null) throw new IllegalArgumentException("argument rank() is null");
        return rank(root, key);
    }
    
    private int rank(Node x, Key key) {
        if (x == null) return 0;
        int cmp = key.compareTo(x.key);
        if (cmp < 0) return rank(x.left, key);
        else if (cmp > 0) return 1 + size(x.left) + rank(x.right, key);
        else return size(x.left);
    }

}

二叉查找树平均情况下查找和插入时间复杂需为1.39logn;最坏情况下为n。

相关文章

  • 极客时间数据结构与算法之美笔记25~26

    二叉树到二叉查找树,是为了查找数据的效率接近logN。 二叉查找树到平衡二叉查找树,是为了防止二叉查找树沦为链表。...

  • 二叉查找树

    1)二叉查找树是什么?2)二叉查找树的插入、删除、查找?3)Go代码实现 一、二叉查找树是什么?二叉查找树(BST...

  • 红黑树

    红黑树的本质就是一棵二叉查找树,所以先从二叉查找树来了解起。 二叉查找树 二叉查找树又称有序二叉树,具有以下特性:...

  • 二叉查找树

    二叉查找树,又称二叉搜索树 二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质: ...

  • 99-数据结构和算法

    难点:二叉树的遍历 红黑树 图的遍历 二叉查找树二叉查找树(binary search tree),二叉查找树在二...

  • 11-二叉查找树

    二叉查找树 1.什么是二叉查找树? 二叉查找树是一种支持数据动态的插入,删除,查找的数据结构。 2.二叉查找树的设...

  • 17张图带你解析红黑树的原理!保证你能看懂!

    二叉查找树 由于红黑树本质上就是一棵二叉查找树,所以在了解红黑树之前,咱们先来看下二叉查找树。 二叉查找树(Bin...

  • 二叉树 堆 2019-04-17

    二叉树 实现一个二叉查找树,并且支持插入、删除、查找操作 实现查找二叉查找树中某个节点的后继、前驱节点 实现二叉树...

  • 6. 二叉树创建-查找

    1. 递归方式实现二叉树的构建2. 树、二叉树、二叉查找树3. 二叉树排序树的理解4. 二叉查找树5. 二叉树的查找

  • 数据结构中的各种树

    一、二叉树 二、二叉查找树(又称二叉排序树,二叉搜索树) 二叉查找树(Binary Search Tree)它或者...

网友评论

      本文标题:二叉查找树

      本文链接:https://www.haomeiwen.com/subject/zpzljxtx.html