1 TreeMap的本质是什么?
二叉树
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
NavigableMap 翻译之后叫做: 可导航的Map
//比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制
private final Comparator<? super K> comparator;
//TreeMap红-黑节点,为TreeMap的内部类
private transient Entry<K,V> root = null;
//容器大小
private transient int size = 0;
//TreeMap修改次数
private transient int modCount;
2 排序方式
可以自定义排序方式,或者默认按照插入属性排序
3 HashMap,LinkedHashMap,TreeMap 什么时候用哪种?
LinkedHashMap继承自HashMap。如果只需要存储功能,使用HashMap与LinkedHashMap是一种更好的选择;如果还需要保证统计性能或者需要对Key按照一定规则进行排序,那么使用treemap是一种更好的选择。LinkedHashMap还额外保证了Map的遍历顺序可以与put顺序一致,解决了HashMap本身无序的问题。
HashMap和LinkedHashMap做的比较不好,此时我们可以使用TreeMap。TreeMap的key按照自然顺序进行排序或者根据创建映射时提供的Comparator接口进行排序。TreeMap为增、删、改、查这些操作提供了log(N)的时间开销,从存储角度而言,这比HashMap与LinkedHashMap的o(1)时间负责度要差些;但是在统计性能上,TreeMap同时可以保证log(N)的时间开销,这又比HashMap和LinkedHashMap的o(N)时间复杂度好不少。
4 特点
它是线程不安全的,但是可以通过下面方式设置成线程安全
Map m = Collections.synchronizedSortedMap(new TreeMap(…));
5 排序的不同,可以根据构造方法的不同去实现排序的不同
6 key不可以为null,但是如果比较器对null做处理的话就可以
7 如果没有设置自定义的比较器,那我们将获取key的类型所在的比较器,例如String 类型继承了Comparable,那么我们就默认使用String类的比较器。
8 put方法逻辑
- 首先判断是不是第一个元素,如果是则作为根节点
- 判断是否有自定义比较器,否则判断key是否为null,否则就用类自带的比较器去存储数据
public V put(K key, V value) {
Entry<K,V> 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<K,V> 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<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
9 get方法逻辑
- 首先判断输入的key通过比较器是否小于二叉树中最小的元素,或者大于最大的,如果是,返回null
- 然后接着去获取元素,判断是否是自定义的比较器,否则判断key是否为null,否则根据key类型获取自带的比较器去获取数据
public V get(Object key) { Entry<K,V> p = getEntry(key); return (p==null ? null : p.value); }
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
总结:
- 实现方式
HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。
(1)HashMap(): 构建一个空的哈希映像
(2)HashMap(Map m): 构建一个哈希映像,并且添加映像m的所有映射
(3)HashMap(int initialCapacity): 构建一个拥有特定容量的空的哈希映像
(4)HashMap(int initialCapacity, float loadFactor): 构建一个拥有特定容量和加载因子的空的哈希映像
TreeMap:基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
(1)TreeMap():构建一个空的映像树
(2)TreeMap(Map m): 构建一个映像树,并且添加映像m中所有元素
(3)TreeMap(Comparator c): 构建一个映像树,并且使用特定的比较器对关键字进行排序
(4)TreeMap(SortedMap s): 构建一个映像树,添加映像树s中所有映射,并且使用与有序映像s相同的比较器排序 - 用途
HashMap:适用于在Map中插入、删除和定位元素。
TreeMap:适用于按自然顺序或自定义顺序遍历键(key)。
HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap.
3 视频中讲错的地方
public V put(K key, V value) //这个方法会执行
public final V put(K key, V value) //调用put方法的时候该方法不会被调用,如有问题请发评论告知
public V get(Object key) { //这个方法会执行 Entry<K,V> p = getEntry(key); return (p==null ? null : p.value); }
public final V get(Object key) {//调用get方法的时候该方法不会被调用,如有问题请发评论告知
return !inRange(key) ? null : m.get(key);
}