1.データ構造
TreeMapの基礎となるデータ構造は赤黒ツリーであり、HashMapの赤黒ツリー構造と同じです。違いは、TreeMapは、左ノードが小さく右ノードが大きい赤黒ツリーを利用してキーに従ってソートするため、各要素を赤黒ツリーの適切な位置に挿入して、キーのサイズ関係を維持し、キーのソートに適していることです。シーン。最下層はバランスの取れた赤黒ツリー構造を使用しているため、containsKey、get、put、removeなどのメソッドの時間の複雑さはすべてlog(n)です。
ソースコード
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
//比较器,如果外部有传进来Comparator比较器,首先用外部的
//如果外部比较器为空,则使用key实现的Comparable的compareTo方法
private final Comparator<? super K> comparator;
//红黑树的根节点
private transient Entry<K,V> root;
//红黑树中已有的元素大小
private transient int size = 0;
//树结构变化的版本号,用于迭代过程中的快速失败场景
private transient int modCount = 0;
//红黑树的节点
static final class Entry<K,V> implements Map.Entry<K,V> {
}
}
2.新しく
追加されたキーと値のソースコードを以下に示します。
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable{
public V put(K key, V value) {
Entry<K,V> t = root;
//判断红黑树的节点是否为空,为空的话,新增的节点直接作为根节点
if (t == null) {
//compare方法限制了key不能为null
compare(key, key);
//成为根节点
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
//根据红黑树左小右大的特性,进行判断,找到新增节点的父节点
Comparator<? super K> cpr = comparator;
if (cpr != null) {
//自旋找到key应该新增的位置
do {
//一次循环结束时,parent就是上次比过的对象
parent = t;
//通过compare来比较key的大小
cmp = cpr.compare(key, t.key);
//key小于t,把t左边的值赋予t,因为红黑树左边的值比较小,循环再比
if (cmp < 0)
t = t.left;
//key大于t,把t右边的值赋予t,因为红黑树右边的值比较大,循环再比
else if (cmp > 0)
t = t.right;
//如果相等的话,直接覆盖原值
else
return t.setValue(value);
//t为空,说明已经到叶子节点了
} 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);
//cmp代表最后一次对比的大小,小于0 ,代表e在上一节点的左边
if (cmp < 0)
parent.left = e;
//大于0 ,代表e在上一节点的右边,相等的情况第二步已经处理了
else
parent.right = e;
//着色旋转,直至达到平衡
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
}
ソースコード分析
1.新しいノードを追加するときは、左が小さく右が大きいという赤黒の木の特性を使用して、ノードの値がnullになるまでルートノードを継続的に検索します。ノードがnullの場合は、リーフノードに到達したことを意味します。
2.検索プロセス中に、キー値がすでに存在することが判明した場合、そのキー値は直接上書きされます。
3.TreeMapはnullキーをサポートしていません。