功能:将Set中的元素按照一定的规则进行排序存储。
在其源码的内部实现中(如下),可以看到TreeSet时借助了TreeMap来实现的。
public TreeSet() {
this(new TreeMap());
}
TreeSet(NavigableMap m) {
this.m = m;
}
public boolean add(E e) {
// private static final Object PRESENT = new Object();
return m.put(e, PRESENT)==null;
}
从add方法中可以看到直接将e其作为key,value = new Object() 保存在了TreeMap中。
下面来看一下TreeMap类中put方法的内部实现哈
public TreeMap() {
comparator = null;
}
TreeMap.put(key,value)的实现思想比较简单:
1)就是实现了一个二叉排序树:要么是空树,要么满足以下条件:若左子树不空,则左子树所有结点的值均小于根结点的值,若右子树不空,右子树所有结点的值均大于根结点的值;左子树和右子树也是一颗二叉排序树。
2)具体为:从root节点开始遍历,利用比较器comparator来比较node.key与key的大小来确定此key应该存放的位置。注意:comparator可能为null,如果为null,则使用key的natural ordering(自然顺序),例如:没有指定comparator的String 类型key 的结果就是字典排序。
public V put(K key, V value) {
Entry t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry parent;
// split comparator and comparable paths
Comparator super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable super K> k = (Comparable super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
经常我们会这里来遍历已经排好序的TreeSet
for (String key : treeSet) {
//...
}
那么,里面是如何来实现从最小的元素开始依次开始取元素的呢?
简单来说:由于存储是使用的二叉树排序的思想,因此对二叉树进行中序遍历即可得到有序的结果集。
从源码来分析,具体这就要看TreeMap中的keySet()方法的内部实现了
public Set keySet() {
return navigableKeySet();
}
public NavigableSet navigableKeySet() {
KeySet nks = navigableKeySet;
return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
}
这里的KeySet这个类就是关键了。
static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
private final NavigableMap?> m;
KeySet(NavigableMap?> map) { m = map; }
public Iterator iterator() {
if (m instanceof TreeMap)
return ((TreeMap?>)m).keyIterator();
else
return ((TreeMap.NavigableSubMap?>)m).keyIterator();
}
//...省略了不需要关注的代码
}
从上面KeySet的iterator的实现中可以看到,通过如下的方法得到了类型为KeyIterator的迭代器。
Iterator keyIterator() {
return new KeyIterator(getFirstEntry());
}
/**
* Returns the first Entry in the TreeMap (according to the TreeMap's
* key-sort function). Returns null if the TreeMap is empty.
*/
final Entry getFirstEntry() {
Entry p = root;
if (p != null)
while (p.left != null)
p = p.left;
return p;
}
getFirstEntry函数的功能:找到排序结果中最小的那个元素。
下面主要看下 KeyIterator 这个类
这个类的next方法就是用来获取TreeSet中的下一个排好序的元素的。
具体实现思路为:由于上面讲解的put方法中我们知道是根据“左根右”的思想来存储的[最小值,中间值,最大值],因此这里的获取最小值的思路也是如此。
final class KeyIterator extends PrivateEntryIterator<K> {
KeyIterator(Entry first) {
super(first);
}
public K next() {
return nextEntry().key;
}
}
final Entry nextEntry() {
Entry e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);
lastReturned = e;
return e;
}
/**
* Returns the successor of the specified Entry, or null if no such.
*/
static TreeMap.Entry successor(Entry t) {
if (t == null)
return null;
else if (t.right != null) {//判断t节点的右边还有没有元素,如果有取出最小的。
Entry p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {//如果此时t的右边没有元素可遍历了,则遍历t的父节点的父节点
Entry p = t.parent;
Entry ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
比较简单哈,就是根据顺序存储,然后按照一定的顺序取出。