zoukankan      html  css  js  c++  java
  • [Java] TreeMap

    TreeMap 实现了 SortedMap 和 NavigableMap 接口,所有本文还会记录 SortedMap 和 NavigableMap 的阅读笔记。

    SortedMap

    1. 排序的比较应该和 equals(Object) 保持一致

    2. 应该提供四种“标准”的构造器

      1). 无参构造器

      2). 带一个 Comparator 为参数的构造器

      3). 带一个 Map 为参数的构造器

      4). 带一个 SortedMap 为参数的构造器

    3.  subMap ,  headMap ,  tailMap ,  KeySet values entrySet  等方法返回的 Map 或 Set 和 SortedMap 本身使用同一份数据,所以对 subMap 返回的 Map 进行修改,同样会反映到 SortedMap 上。

     

    NavigableMap

    1. lowerEntry, floorEntry, ceilingEntry, higherEntry 分别返回 小于、小于或等于,大于或等于,以及大于给定 key 的 Map.Entry。这类型的方法用于定位离目标给定值最近的元素。

    2. 增长序 map 的操作比递减序的 map 的操作要快。

    3. 返回 entry 的方法返回的是那一刻的 entry 快照,所以通常不支持 Entry.setValue 方法。

    例如, TreeMap 实现 NavigableMap 的 firstEntry,返回会的就是根据给定 entry 的 key, value 新建的不可变 

    SimpleImmutableEntry 对象。

    4. pollFirstEntry 删除并返回第一个元素

     

    TreeMap

    1. 基于红黑树的实现

    2. 根据自然序,或者给定的比较器是内部元素保持有序。

    3. 提供复杂度为 log(n) 的 containsKey, get, put, remove 操作

    4. itertator 采用 fast-fail 机制

    5. values 继承于 Collection, EntrySet 和 KeySet 则继承于 Set

    6. DeletionEntry 删除指定的元素,fixAfterDeletion 对删除后的树节点进行再平衡,使得 TreeMap 保持红黑树的特性。

    7. containsValue(Object) 通过遍历所有元素,来判断是否包含指定的值为 value。因此,效率低。

        public boolean containsValue(Object value) {
            for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
                if (valEquals(value, e.value))
                    return true;
            return false;
        }

    8. getFirstEntry 返回树中最左下角的元素

        final Entry<K,V> getFirstEntry() {
            Entry<K,V> p = root;
            if (p != null)
                while (p.left != null)
                    p = p.left;
            return p;
        }

    getLastEntry 返回树中最右下角的元素

        final Entry<K,V> getLastEntry() {
            Entry<K,V> p = root;
            if (p != null)
                while (p.right != null)
                    p = p.right;
            return p;
        }
    

      

    9. successor(Entry e) 

    当 e 为 null 时,返回 null

    当 e 有右子节点时,则返回右子节点的最左下角后代节点

    当 e 没有右子节点时,返回一个离 e 最近的祖先节点,该祖先节的左孩子也是 e 的祖先节点。

        static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
            if (t == null)
                return null;
            else if (t.right != null) {
                Entry<K,V> p = t.right;
                while (p.left != null)
                    p = p.left;
                return p;
            } else {
                Entry<K,V> p = t.parent;
                Entry<K,V> ch = t;
                while (p != null && ch == p.right) {
                    ch = p;
                    p = p.parent;
                }
                return p;
            }
        }

    10. prodecessor(Entry e) 和 successor(Entry e) 思路相似。

    当 e 为 null 时,返回 null

    当 e 有左子节点时,则返回左子节点的最右下角后代节点

    当 e 没有左子节点时,返回一个离 e 最近的祖先节点,该祖先节的右孩子也是 e 的祖先节点。

        static <K,V> Entry<K,V> predecessor(Entry<K,V> t) {
            if (t == null)
                return null;
            else if (t.left != null) {
                Entry<K,V> p = t.left;
                while (p.right != null)
                    p = p.right;
                return p;
            } else {
                Entry<K,V> p = t.parent;
                Entry<K,V> ch = t;
                while (p != null && ch == p.left) {
                    ch = p;
                    p = p.parent;
                }
                return p;
            }
        }

    11. get(Object):VgetEntry(Object):Entry 的不同点在于,前者返回 V, 而后者返回 Entry。获取的算法一样,因为 get 是基于 getEntry 来实现的。

        public V get(Object key) {
            Entry<K,V> p = getEntry(key);
            return (p==null ? null : p.value);
        }

    12. containsKey(Object) 同样也是基于 getEntry 来实现的

        public boolean containsKey(Object key) {
            return getEntry(key) != null;
        }
    

    13. computeRedLevel(int) ,应用于复制一个 map 到当前为空的 TreeMap 的操作中。复制后的 TreeMap 应该是一棵完全二叉树(complete binary tree),通过将其中满足完美二叉树(perfect binary tree)部分的节点涂黑,则可以简单地实现红黑树的黑属性

        private static int computeRedLevel(int sz) {
            int level = 0;
            for (int m = sz - 1; m >= 0; m = m / 2 - 1)
                level++;
            return level;
        }

    下面是一个完全二叉树的例子,其中满足完美二叉树的只有 0 - 7 个节点,也就是 0 - 2 层。0 - 2 层的节点全部涂黑色,最后一层则全部涂红色。则最方便地满足红黑树的特性。

    14. buildFromSorted, 采用递归的思路,先构建后节点的左子树,在构建好节点的右子树,最后和节点组合成一个完整的子树。

    15. putAll(Map)

    当 TreeMap 没有元素,Map 是一个 sortMap, 并且 Map 的比较器等于 TreeMap 的比较器,则采用 buildFormSorted 来构建 TreeMap。

    否则,将 Map 中每个 mapping,通过调用 put(K, V) 来插入 TreeMap 中。

        public void putAll(Map<? extends K, ? extends V> map) {
            int mapSize = map.size();
            if (size==0 && mapSize!=0 && map instanceof SortedMap) {
                Comparator<?> c = ((SortedMap<?,?>)map).comparator();
                if (c == comparator || (c != null && c.equals(comparator))) {
                    ++modCount;
                    try {
                        buildFromSorted(mapSize, map.entrySet().iterator(),
                                        null, null);
                    } catch (java.io.IOException cannotHappen) {
                    } catch (ClassNotFoundException cannotHappen) {
                    }
                    return;
                }
            }
            super.putAll(map);
        }

    16. getEntry, getEntryUsingComparator, getCeilingEntry, getFloorEntry, getHigherEntry, getLowerEntry 都是基于二分查找思路来实现元素操作。

    17. put(K, V)

    当已存在 key 和 K 相等的 Entry, 则直接更新这个 Entry 的 value 值。

    否则,插入新的 Entry ,然后自平衡树结构。

    18. remove(Object),删除指定节点,然后自平衡树结构

    19. clear(), 将 root 至 null 即可

        public void clear() {
            modCount++;
            size = 0;
            root = null;
        }
    

    20.  firstEntry 返回不可变的 Entry , getFirstEntry 则返回可变的 Entry。同样关系的还有:lastEntrygetLastEntrylowerEntrygetLowerEntry, higherEntrygetHigherEntry

      

    Jdk 版本: jdk1.8.0_31.jdk

  • 相关阅读:
    [Maven实战-许晓斌]-[第二章]-2.2基于UNIX系统安装maven
    [Maven实战-许晓斌]-[第二章]-2.1在Windows上安装maven
    【sonar-block】Use try-with-resources or close this "BufferedInputStream" in a "finally" clause.
    sonar阻断级别错误(block)简单汇总
    让子类使用父类的Logger
    集合的addAll方法--list.addAll(null)会报错--java.lang.NullPointerException
    nice
    ERROR 1524 (HY000): Plugin 'auth_socket' is not loaded
    Ubuntu 系统修改root密码后,无需密码亦可登录
    MySQL 查找今年的数据
  • 原文地址:https://www.cnblogs.com/TonyYPZhang/p/5747850.html
Copyright © 2011-2022 走看看