给jdk写注释系列之jdk1.6容器(8)-TreeSet&NavigableMap&NavigableSet源码解析
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
public interface NavigableSet<E> extends SortedSet<E> {
E lower(E e);
E floor(E e);
E ceiling(E e);
E higher(E e);
E pollFirst();
E pollLast();
Iterator<E> iterator();
NavigableSet<E> descendingSet();
Iterator<E> descendingIterator();
NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive);
NavigableSet<E> headSet(E toElement, boolean inclusive);
NavigableSet<E> tailSet(E fromElement, boolean inclusive);
SortedSet<E> subSet(E fromElement, E toElement);
SortedSet<E> headSet(E toElement);
SortedSet<E> tailSet(E fromElement);
}
// 底层使用NavigableMap来保存TreeSet的元素
private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map
// 由于Set只使用到了Map的key,所以此处定义一个静态的常量Object类,来充当Map的value
private static final Object PRESENT = new Object();
我想,对于PRESENT这个常量不用多解释了吧,在HashSet中解释过的。至于这里的NavigableMap是什么东西,下面说。
/**
* 使用指定的navigable map来构造TreeSet
*/
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
} /**
* 默认构造方法,底层使用TreeMap来存储TreeSet元素
*/
public TreeSet() {
this(new TreeMap<E,Object>());
} /**
* 使用指定的构造器,构造一个TreeMap来保存TreeSet的数据
*/
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<E,Object>(comparator));
} /**
* 构造一个指定Collection参数的TreeSet
*/
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
} /**
* 构造一个指定SortedMap的TreeSet,根据SortedMap的比较器来来维持TreeSet的顺序
*/
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
public interface NavigableMap<K,V> extends SortedMap<K,V> {
// 获取小于指定key的第一个节点对象
Map.Entry<K,V> lowerEntry(K key);
// 获取小于指定key的第一个key
K lowerKey(K key);
// 获取小于或等于指定key的第一个节点对象
Map.Entry<K,V> floorEntry(K key);
// 获取小于或等于指定key的第一个key
K floorKey(K key);
// 获取大于或等于指定key的第一个节点对象
Map.Entry<K,V> ceilingEntry(K key);
// 获取大于或等于指定key的第一个key
K ceilingKey(K key);
// 获取大于指定key的第一个节点对象
Map.Entry<K,V> higherEntry(K key);
// 获取大于指定key的第一个key
K higherKey(K key);
// 获取Map的第一个(最小的)节点对象
Map.Entry<K,V> firstEntry();
// 获取Map的最后一个(最大的)节点对象
Map.Entry<K,V> lastEntry();
// 获取Map的第一个节点对象,并从Map中移除改节点
Map.Entry<K,V> pollFirstEntry();
// 获取Map的最后一个节点对象,并从Map中移除改节点
Map.Entry<K,V> pollLastEntry();
// 返回当前Map的逆序Map集合
NavigableMap<K,V> descendingMap();
// 返回当前Map中包含的所有key的Set集合
NavigableSet<K> navigableKeySet();
// 返回当前map的逆序Set集合,Set由key组成
NavigableSet<K> descendingKeySet();
// 返回当前map中介于fromKey(fromInclusive是否包含)和toKey(toInclusive是否包含) 之间的子map
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive);
// 返回介于map第一个元素到toKey(inInclusive是否包含)之间的子map
NavigableMap<K,V> headMap(K toKey, boolean inclusive);
// 返回当前map中介于fromKey(inInclusive是否包含) 到map最后一个元素之间的子map
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
// 返回当前map中介于fromKey(包含)和toKey(不包含)之间的子map
SortedMap<K,V> subMap(K fromKey, K toKey);
// 返回介于map第一个元素到toKey(不包含)之间的子map
SortedMap<K,V> headMap(K toKey);
// 返回当前map中介于fromKey(包含) 到map最后一个元素之间的子map
SortedMap<K,V> tailMap(K fromKey);
}
/**
* 利用NavigableMap的put方法实现add方法
*/
public boolean add(E e) {
return m .put(e, PRESENT)== null;
} /**
* 利用NavigableMap的remove方法实现add方法
*/
public boolean remove(Object o) {
return m .remove(o)==PRESENT;
} /**
* 添加一个集合到TreeSet中
*/
public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
// 如果集合c是SortedSet的子类,并且m是TreeMap的子类,则用下面的方法添加(主要为了检查是否需要重新排序)
if (m .size()==0 && c.size() > 0 &&
c instanceof SortedSet &&
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
// 取出集合c的比较器
Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
// 取出当前set的比较器
Comparator<? super E> mc = map.comparator();
// 如果上面的两种比较器是同一个的话(==或equals),当然TreeSet和TreeMap默认构造方法比较器都是null,这里也是==的
if (cc==mc || (cc != null && cc.equals(mc))) {
// 将集合c在当前set集合顺序的基础上,按顺序插入
map.addAllForTreeSet(set, PRESENT);
return true;
}
} // 不需要排序的话就按普通方法,调用父类AbstractCollection的addAll方法(将集合c添加到Set尾部)
return super.addAll(c);
} /**
* 添加一个集合到TreeSet中
*/
public boolean removeAll(Collection<?> c) {
boolean modified = false; // 判断当前TreeSet元素个数和指定集合c的元素个数,目的是减少遍历次数
if (size() > c.size()) {
// 如果当前TreeSet元素多,则遍历集合c,将集合c中的元素一个个删除
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
// 如果集合c元素多,则遍历当前TreeSet,将集合c中包含的元素一个个删除
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
4.是否包含
/**
* 利用TreeMap的containsKey方法实现contains方法
*/
public boolean contains(Object o) {
return m .containsKey(o);
} /**
* 检查是否包含指定集合中所有元素,该方法在AbstractCollection中
*/
public boolean containsAll(Collection<?> c) {
// 取得集合c的迭代器Iterator
Iterator<?> e = c.iterator();
// 遍历迭代器,只要集合c中有一个元素不属于当前HashSet,则返回false
while (e.hasNext())
if (!contains(e.next()))
return false;
return true;
}
5.容量检查
/**
* Returns the number of elements in this set (its cardinality).
*
* @return the number of elements in this set (its cardinality)
*/
public int size() {
return map .size();
} /**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt> true</tt> if this set contains no elements
*/
public boolean isEmpty() {
return map .isEmpty();
}
public E pollFirst() {
Map.Entry<E,?> e = m.pollFirstEntry();
return (e == null)? null : e.getKey();
}
public E pollLast() {
Map.Entry<E,?> e = m.pollLastEntry();
return (e == null)? null : e.getKey();
}
果然没有猜错,这些方法还是基于NavigableMap实现的,要明白其具体实现代码,我们来看看TreeMap中是怎么实现NavigableMap接口中这些方法的。
public Map.Entry<K,V> pollFirstEntry() {
// 取得当前Map第一个节点
Entry<K,V> p = getFirstEntry();
// 返回一个只包含key、value的简单Entry对象,exportEntry不必深究也很简单
Map.Entry<K,V> result = exportEntry(p);
// 如果节点不为空,将节点删除
if (p != null)
deleteEntry(p);
return result;
}
public Map.Entry<K,V> pollLastEntry() {
// 取得当前Map第一个节点
Entry<K,V> p = getLastEntry();
// 返回一个只包含key、value的简单Entry对象,exportEntry不必深究也很简单
Map.Entry<K,V> result = exportEntry(p);
// 如果节点不为空,将节点删除
if (p != null)
deleteEntry(p);
return result;
}
/**
* Returns the first Entry in the TreeMap (according to the TreeMap's
* key -sort function). Returns null if the TreeMap is empty.
*/
final Entry<K,V> getFirstEntry() {
// 取得根节点
Entry<K,V> p = root;
if (p != null)
// 循环取根节点的left,直到取到最左边的一个节点,也就是取得最小值(红黑树原则最左边最小)
while (p.left != null)
p = p. left;
return p;
}
/**
* Returns the last Entry in the TreeMap (according to the TreeMap's
* key -sort function). Returns null if the TreeMap is empty.
*/
final Entry<K,V> getLastEntry() {
// 取得根节点
Entry<K,V> p = root;
if (p != null)
// 循环取根节点的right,直到取到最右边的一个节点,也就是取得最大值(红黑树原则最右边最大)
while (p.right != null)
p = p. right;
return p;
}
在明白了红黑树的原则之后,这几个取第一个和最后一个的方法看起来还是很简单的,我们再来看下其他方法的实现:
public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive) {
// key越界检查,key怎么越界呢,当然是因为TreMap已经对key排序了,不细看
if (!inRange(fromKey, fromInclusive))
throw new IllegalArgumentException( "fromKey out of range" );
if (!inRange(toKey, toInclusive))
throw new IllegalArgumentException( "toKey out of range" );
// 返回AscendingSubMap对象
return new AscendingSubMap(m,
false, fromKey, fromInclusive,
false, toKey, toInclusive);
}
AscendingSubMap是NavigableSubMap子类,该构造方法直接调用NavigableSubMap,继续看:
static abstract class NavigableSubMap<K,V> extends AbstractMap<K,V>
implements NavigableMap<K,V>, java.io.Serializable {
/**
* The backing map.
*/
final TreeMap<K,V> m; // 底层使用原始TreeMap提供数据操作 final K lo, hi;
final boolean fromStart, toEnd;
final boolean loInclusive, hiInclusive; NavigableSubMap(TreeMap<K,V> m,
boolean fromStart, K lo, boolean loInclusive,
boolean toEnd, K hi, boolean hiInclusive) {
if (!fromStart && !toEnd) {
if (m.compare(lo, hi) > 0)
throw new IllegalArgumentException( "fromKey > toKey" );
} else {
if (!fromStart) // type check
m.compare(lo, lo);
if (!toEnd)
m.compare(hi, hi);
} // 记录边界
this.m = m;
this.fromStart = fromStart;
this.lo = lo;
this.loInclusive = loInclusive;
this.toEnd = toEnd;
this.hi = hi;
this.hiInclusive = hiInclusive;
}
... ...
... ... public final V put(K key, V value) {
// 边界检查,如果不在边界范围内,则抛出异常
if (!inRange(key))
throw new IllegalArgumentException( "key out of range" );
return m .put(key, value);
}
public final V get(Object key) {
return !inRange(key)? null : m.get(key);
}
}
给jdk写注释系列之jdk1.6容器(8)-TreeSet&NavigableMap&NavigableSet源码解析的更多相关文章
- 给jdk写注释系列之jdk1.6容器(11)-Queue之ArrayDeque源码解析
前面讲了Stack是一种先进后出的数据结构:栈,那么对应的Queue是一种先进先出(First In First Out)的数据结构:队列. 对比一下Stack,Queue是一种先进先出的容 ...
- 给jdk写注释系列之jdk1.6容器(13)-总结篇之Java集合与数据结构
是的,这篇blogs是一个总结篇,最开始的时候我提到过,对于java容器或集合的学习也可以看做是对数据结构的学习与应用.在前面我们分析了很多的java容器,也接触了好多种常用的数据结构,今天 ...
- 给jdk写注释系列之jdk1.6容器(9)-Strategy设计模式之Comparable&Comparator接口
前面我们说TreeMap和TreeSet都是有顺序的集合,而顺序的维持是要靠一个比较器Comparator或者map的key实现Comparable接口. 既然说到排序,首先我们不用去关心什 ...
- 给jdk写注释系列之jdk1.6容器(7)-TreeMap源码解析
TreeMap是基于红黑树结构实现的一种Map,要分析TreeMap的实现首先就要对红黑树有所了解. 要了解什么是红黑树,就要了解它的存在主要是为了解决什么问题,对比其他数据结构比如数组,链 ...
- 给jdk写注释系列之jdk1.6容器(12)-PriorityQueue源码解析
PriorityQueue是一种什么样的容器呢?看过前面的几个jdk容器分析的话,看到Queue这个单词你一定会,哦~这是一种队列.是的,PriorityQueue是一种队列,但是它又是一种什么样的队 ...
- 给jdk写注释系列之jdk1.6容器(10)-Stack&Vector源码解析
前面我们已经接触过几种数据结构了,有数组.链表.Hash表.红黑树(二叉查询树),今天再来看另外一种数据结构:栈. 什么是栈呢,我就不找它具体的定义了,直接举个例子,栈就相当于一个很窄的木桶 ...
- 给jdk写注释系列之jdk1.6容器(6)-HashSet源码解析&Map迭代器
今天的主角是HashSet,Set是什么东东,当然也是一种java容器了. 现在再看到Hash心底里有没有会心一笑呢,这里不再赘述hash的概念原理等一大堆东西了(不懂得需要先回去看下Has ...
- 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析
前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表).接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持 ...
- 给jdk写注释系列之jdk1.6容器(4)-HashMap源码解析
前面了解了jdk容器中的两种List,回忆一下怎么从list中取值(也就是做查询),是通过index索引位置对不对,由于存入list的元素时安装插入顺序存储的,所以index索引也就是插入的次序. M ...
随机推荐
- boost::bind 和 boost::function 基本用法
这是一篇介绍bind和function用法的文章,起因是近来读陈硕的文章,提到用bind和function替代继承,于是就熟悉了下bind和function的用法,都是一些网上都有的知识,记录一下,期 ...
- 深入探究frame和bounds的区别以及setbounds使用
[转自]http://blog.csdn.net/hherima/article/details/39501857 在iOS开发中经常遇到两个词Frame和bounds,本文主要阐述Frame和bou ...
- CodeForces 567A Gerald is into Art
http://codeforces.com/problemset/problem/567/A A. Lineland Mail time limit per test 3 seconds memory ...
- BestCoder Round #68 (div.2) geometry(hdu 5605)
geometry Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Su ...
- [ASP.NET MVC] Child actions are not allowed to perform redirect
我在Umbraco平台下,用MVC(SurfaceController)开发时,遇到这个问题 MemberEdit是一个partial View [HttpGet] [ActionName(" ...
- SPOJ 375 (树链剖分 - 边权剖分 - 修改单边权)
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28982#problem/I 给你一棵有边权的树,有两个操作:一个操作是输出l到 ...
- 让人眼花缭乱的 RSS 版本0.90、0.91、0.92、0.93、0.94、1.0 和 2.0
1.0的规范 http://web.resource.org/rss/1.0/spec 2.0的规范 http://cyber.law.harvard.edu/rss/rss.html 一个介绍什么是 ...
- Proactor设计模式:单线程高并发
Boost::Asio为同步和异步操作提供了并行支持,异步支持基于前摄器模式,这种模式的优点和缺点可能比只同步或反应器方法要低. 让我们检查一下Boost::Asio是如何实现前摄器模式的,没有引用基 ...
- SQL 表锁(转)
其实你可以使用事务处理 比方说在一个字段里面添加一个boolean 的字段当你要处理该字段的时候就 True 哪么别的人都不可以进行操作 如果是False 哪么就可以进行操作--呵可--我是这样的 ...
- Squid代理服务器&&搭建透明代理网关服务器
案例需求 ——公司选用RHEL5服务器作为网关,为了有效节省网络带宽.提高局域网访问Internet的速度,需要在网关服务器上搭建代理服务,并结合防火墙策略实现透明代理,以减少客户端的重复设置工作 需 ...