TreeMap的用法

构造方法

// 默认构造函数。使用该构造函数,TreeMap中的元素按照自然排序进行排列。
TreeMap()

// 创建的TreeMap包含Map
TreeMap(Map<? extends K, ? extends V> copyFrom)

// 指定Tree的比较器
TreeMap(Comparator<? super K> comparator)

// 创建的TreeSet包含copyFrom
TreeMap(SortedMap<K, ? extends V> copyFrom)

常见用法
比较器。用来给TreeMap排序

private final Comparator<? super K> comparator;

TreeMap是红黑树实现的,root是红黑树的根节点

private transient Entry<K,V> root = null;

红黑树的节点总数

private transient int size = 0;

记录红黑树的修改次数

private transient int modCount = 0;

返回TreeMap中是否保护“键(key)”

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

返回TreeMap中是否保护"值(value)"

public boolean containsValue(Object value) {
// getFirstEntry() 是返回红黑树的第一个节点
// successor(e) 是获取节点e的后继节点
for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
          if (valEquals(value, e.value))
          return true;
    return false;
}

获取“键(key)”对应的“值(value)”

public V get(Object key) {
// 获取“键”为key的节点(p)
Entry<K,V> p = getEntry(key);
// 若节点(p)为null,返回null;否则,返回节点对应的值
    return (p==null ? null : p.value);
}

public Comparator<? super K> comparator() {
   return comparator;
}

获取第一个节点对应的key

public K firstKey() {
     return key(getFirstEntry());
}

获取最后一个节点对应的key

public K lastKey() {
    return key(getLastEntry());
}

将map中的全部节点添加到TreeMap中

public void putAll(Map<? extends K, ? extends V> map) {
// 获取map的大小
int mapSize = map.size();
// 如果TreeMap的大小是0,且map的大小不是0,且map是已排序的“key-value对”
if (size==0 && mapSize!=0 && map instanceof SortedMap) {
Comparator c = ((SortedMap)map).comparator();
// 如果TreeMap和map的比较器相等;
// 则将map的元素全部拷贝到TreeMap中,然后返回!
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;
         }
     }
      // 调用AbstractMap中的putAll();
      // AbstractMap中的putAll()又会调用到TreeMap的put()
       super.putAll(map);
  }

获取TreeMap中“键”为key的节点

final Entry<K,V> getEntry(Object key) {
    // 若“比较器”为null,则通过getEntryUsingComparator()获取“键”为key的节点
        if (comparator != null)
       return getEntryUsingComparator(key);
        if (key == null)
          throw new NullPointerException();
       Comparable<? super K> k = (Comparable<? super K>) key;
       // 将p设为根节点
     Entry<K,V> p = root;
         while (p != null) {
          int cmp = k.compareTo(p.key);
             // 若“p的key” < key,则p=“p的左孩子”
         if (cmp < 0)
               p = p.left;
         // 若“p的key” > key,则p=“p的左孩子”
        else if (cmp > 0)
              p = p.right;
          // 若“p的key” = key,则返回节点p
            else
                return p;
        }
       return null;
 }

获取TreeMap中“键”为key的节点(对应TreeMap的比较器不是null的情况)

final Entry<K,V> getEntryUsingComparator(Object key) {
          K k = (K) key;
             Comparator<? super K> cpr = comparator;
          if (cpr != null) {
            // 将p设为根节点
            Entry<K,V> p = root;
               while (p != null) {
               int cmp = cpr.compare(k, p.key);
                 // 若“p的key” < key,则p=“p的左孩子”
               if (cmp < 0)
                  p = p.left;
              // 若“p的key” > key,则p=“p的左孩子”
                else if (cmp > 0)
                     p = p.right;
                // 若“p的key” = key,则返回节点p
               else
                  return p;
            }
      }
    return null;
    }

获取TreeMap中不小于key的最小的节点;
若不存在(即TreeMap中所有节点的键都比key大),就返回null

final Entry<K,V> getCeilingEntry(K key) {
            Entry<K,V> p = root;
            while (p != null) {
               int cmp = compare(key, p.key);
             // 情况一:若“p的key” > key。
               // 若 p 存在左孩子,则设 p=“p的左孩子”;
            // 否则,返回p
              if (cmp < 0) {
                      if (p.left != null)
                       p = p.left;
                    else
                        return p;
                  // 情况二:若“p的key” < key。
               } else if (cmp > 0) {
                 // 若 p 存在右孩子,则设 p=“p的右孩子”
              if (p.right != null) {
                        p = p.right;
                  } else {
                         // 若 p 不存在右孩子,则找出 p 的后继节点,并返回
                    // 注意:这里返回的 “p的后继节点”有2种可能性:第一,null;第二,TreeMap中大于key的最小的节点。
                   //   理解这一点的核心是,getCeilingEntry是从root开始遍历的。
                        //   若getCeilingEntry能走到这一步,那么,它之前“已经遍历过的节点的key”都 > key。
                         //   能理解上面所说的,那么就很容易明白,为什么“p的后继节点”又2种可能性了。
                      Entry<K,V> parent = p.parent;
                   Entry<K,V> ch = p;
                         while (parent != null && ch == parent.right) {
                         ch = parent;
                          parent = parent.parent;
                      }
                       return parent;
                    }
               // 情况三:若“p的key” = key。
          } else
                 return p;
         }
       return null;
        }

获取TreeMap中大于key的最小的节点。
// 若不存在,就返回null。

final Entry<K,V> getHigherEntry(K key) {
       Entry<K,V> p = root;
         while (p != null) {
         int cmp = compare(key, p.key);
           if (cmp < 0) {
               if (p.left != null)
                   p = p.left;
              else
                 return p;
          } else {
              if (p.right != null) {
                 p = p.right;
             } else {
                  Entry<K,V> parent = p.parent;
                  Entry<K,V> ch = p;
                   while (parent != null && ch == parent.right) {
                      ch = parent;
                      parent = parent.parent;
                }
                  return parent;
               }
           }
    }
   return null;
}

删除TreeMap中的键为key的节点,并返回节点的值

public V remove(Object key) {
// 找到键为key的节点
Entry<K,V> p = getEntry(key);
if (p == null)
     return null;
 // 保存节点的值
V oldValue = p.value;
// 删除节点
 deleteEntry(p);
 return oldValue;
 }

清空红黑树

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

获取最后一个节点(对外接口)。

public Map.Entry<K,V> lastEntry() {
       return exportEntry(getLastEntry());
    }

   // 获取第一个节点,并将改节点从TreeMap中删除。
   public Map.Entry<K,V> pollFirstEntry() {
       // 获取第一个节点
        Entry<K,V> p = getFirstEntry();
    Map.Entry<K,V> result = exportEntry(p);
     // 删除第一个节点
     if (p != null)
         deleteEntry(p);
     return result;
  }

 // 获取最后一个节点,并将改节点从TreeMap中删除。
  public Map.Entry<K,V> pollLastEntry() {
     // 获取最后一个节点
     Entry<K,V> p = getLastEntry();
     Map.Entry<K,V> result = exportEntry(p);
    // 删除最后一个节点
    if (p != null)
         deleteEntry(p);
    return result;
}

返回小于key的最大的键值对,没有的话返回null

public Map.Entry<K,V> lowerEntry(K key) {
 return exportEntry(getLowerEntry(key));
}

返回小于key的最大的键值对所对应的KEY,没有的话返回null

public K lowerKey(K key) {
    return keyOrNull(getLowerEntry(key));
}

返回不大于key的最大的键值对所对应的KEY,没有的话返回null

public K floorKey(K key) {
    return keyOrNull(getFloorEntry(key));
}

返回大于key的最小的键值对,没有的话返回null

public Map.Entry<K,V> higherEntry(K key) {
   return exportEntry(getHigherEntry(key));
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容

  • 基于红黑二叉树实现,线程非安全,不允许键对象是null,key不可以重复,value允许重复,存入TreeMap的...
    加一片柠檬233阅读 1,503评论 0 0
  • 一、基本数据类型 注释 单行注释:// 区域注释:/* */ 文档注释:/** */ 数值 对于byte类型而言...
    龙猫小爷阅读 4,257评论 0 16
  • 第1部分 TreeMap介绍 TreeMap 简介 TreeMap 是一个有序的key-value集合,它是通过红...
    张晨辉Allen阅读 1,683评论 1 4
  • 前言 TreeMap TreeMap类继承图 TreeMap的域 TreeMap的构造函数 TreeMap常见Ap...
    HikariCP阅读 693评论 0 1
  • Map接口 Map是 一个键值对的集合。也就是说,一个映射不能包含重复的键,每个键最多映射到一个值。该接口取代了D...
    wame100阅读 777评论 0 0