二叉查找树

2017-09-03  本文已影响0人  囧囧有神2号

定义:一个二叉查找树是一棵二叉树,其中每个节点都含有一个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。

上一篇下一篇

猜你喜欢

热点阅读