TreeMap - 源代码学习笔记
TreeMap 实现了 NavigableMap 接口,而NavigableMap 接口继承于 SortedMap接口。 所有本文还会记录 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。因此,效率低。
|
1
2
3
4
5
6
|
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 返回树中最左下角的元素
|
1
2
3
4
5
6
7
|
final Entry<K,V> getFirstEntry() { Entry<K,V> p = root; if (p != null) while (p.left != null) p = p.left; return p;} |
getLastEntry 返回树中最右下角的元素
|
1
2
3
4
5
6
7
|
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 的祖先节点。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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 的祖先节点。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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):V 和 getEntry(Object):Entry 的不同点在于,前者返回 V, 而后者返回 Entry。获取的算法一样,因为 get 是基于 getEntry 来实现的。
|
1
2
3
4
|
public V get(Object key) { Entry<K,V> p = getEntry(key); return (p==null ? null : p.value);} |
12. containsKey(Object) 同样也是基于 getEntry 来实现的
|
1
2
3
|
public boolean containsKey(Object key) { return getEntry(key) != null;} |
13. computeRedLevel(int) ,应用于复制一个 map 到当前为空的 TreeMap 的操作中。复制后的 TreeMap 应该是一棵完全二叉树(complete binary tree),通过将其中满足完美二叉树(perfect binary tree)部分的节点涂黑,则可以简单地实现红黑树的黑属性。
|
1
2
3
4
5
6
|
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 中。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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 即可
|
1
2
3
4
5
|
public void clear() { modCount++; size = 0; root = null;} |
20. firstEntry 返回不可变的 Entry , getFirstEntry 则返回可变的 Entry。同样关系的还有:lastEntry 和 getLastEntry,lowerEntry 和 getLowerEntry, higherEntry 和 getHigherEntry。
TreeMap - 源代码学习笔记的更多相关文章
- [Java] TreeMap - 源代码学习笔记
TreeMap 实现了 SortedMap 和 NavigableMap 接口,所有本文还会记录 SortedMap 和 NavigableMap 的阅读笔记. SortedMap 1. 排序的比较应 ...
- [Java] LinkedList / Queue - 源代码学习笔记
简单地画了下 LinkedList 的继承关系,如下图.只是画了关注的部分,并不是完整的关系图.本博文涉及的是 Queue, Deque, LinkedList 的源代码阅读笔记.关于 List 接口 ...
- jQuery源代码学习笔记_工具函数_noop/error/now/trim
jQuery源代码学习笔记_工具函数_noop/error/now/trim jquery提供了一系列的工具函数,用于支持其运行,今天主要分析noop/error/now/trim这4个函数: 1.n ...
- [Java] List / ArrayList - 源代码学习笔记
在阅读 List / ArrayList 源代码过程中,做了下面的笔记. LinkedList 的笔记较多,放到了另一篇博文 LinkedList / Queue- 源代码学习笔记 List List ...
- jQuery源代码学习笔记:jQuery.fn.init(selector,context,rootjQuery)代码具体解释
3.1 源代码 init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(&qu ...
- jQuery源代码学习笔记:构造jQuery对象
2.1源代码结构: (function( window, undefined ) { var jQuery = (function() { // 构建jQuery对象 var jQuery = fun ...
- [Java] Map / HashMap - 源代码学习笔记
Map 1. 用于关联 key 和 value 的对象,其中 key 与 key 之间不能重复. 2. 是一个接口,用来代替 Java 早期版本中的 Dictionary 抽象类. 3. 提供三种不同 ...
- jQuery源代码学习笔记_01
如何获取jQuery源代码 1.可以从GitHub上下载到没有合并和压缩的源代码 2.如果要查看兼容IE6-8的版本,请选择1.x-master分支 3.可以使用git clone也可以使用downl ...
- [Java] Collections - 源代码学习笔记
Collection interface 集合接口 1. 在 Collections 体系中,接口 Collection 是根接口 2. 是指一组对象,这些对象被称为 Collection 的元素. ...
随机推荐
- Asp.net core 学习笔记 ( HttpClient )
2018-09-18 core 2.1 之后有新的方案咯 http://www.talkingdotnet.com/3-ways-to-use-httpclientfactory-in-asp-net ...
- Python量化库大全
https://zhuanlan.zhihu.com/p/26983703?utm_source=wechat_session&utm_medium=social 这个网址上详细介绍了,做量化 ...
- VIM编辑器和VI编辑器的区别
vi 和vim 的区别 写在前面:这个两个"东西"着实让我烦恼一阵子,但是自己一直没当回事,但是遇到了好几次再决定彻底把他们搞的明白,一下是我通过查找资料了解到的关于这两个编辑器的 ...
- spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix
spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix 首先application.yml / applicatoin.propreties的配置项:fe ...
- Shell Trap信号管理
trap命令用于指定在接收到信号后将要采取的动作.常见的用途是在脚本程序被中断时完成清理工作.不过,这次我遇到它,是因为客户有个需求:从终端访问服务器的用户,其登陆服务器后会自动运行某个命令,例如打开 ...
- CentOS上安装seafile
一.安装python2.7.14(CentOS7上python默认版本是Python 2.7.5 ,不需要安装)1.安装依赖包[root@web01 ~]# yum -y install zlib z ...
- OSPF - 1,基础
1,OSPF知识点a)在OSPF中,如果是环回口宣告进OSPF,不管宣告时配置的是多少位掩码,路由器收到的都是32位.(EIGRP配了多少位就收到多少位).好处:EIGRP中,在PING包发起时如果在 ...
- c++-pimer-plus-6th-chapter02
<C++ primer plus 英文版 第六版>娓娓道来.这个是上下分册.而且,出版时间是最新的2015年,买回来发现网上的勘误基本都被纠正过来了,极个别错误没有影响到理解,好哎!而且发 ...
- 3月26 document的练习
1.Window.document对象 一.找到元素: docunment.getElementById("id"):根据id找,最多找一个: var a =docunme ...
- 安装sql 2008步骤以及所遇到的问题
下载网址:http://www.xiazaiba.com/html/4610.html 安装步骤: 1. 在Windows7操作系统系,启动Microsoft SQL 2008安装程序后,系统兼容性 ...