HashMap對象沒有順序,TreeMap實現是排序平衡二叉樹,大致是紅黑樹,樹可以排序。根據根節點比較左小右大的特點,注意的是按鍵排序,值不排序
。
對象只要實現comparable
可以排序,重寫compareTo(Object obj)
實現排序。類不能實現可以使用Compartor
這個比較器必須實現compare(String o1, String o2)
方法
構造方法
1.第一個默認TreeMap類,比較自定義對象要實現Comparabe接口比較器,重寫compareTo方法
2.第二個比較TreeMap參數要接收Compartor比較器對象。重寫Compartor接口中compare方法,比較靈活
public TreeMap() {
comparator = null;
}
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
TreeMap的簡單使用,按鍵字母正排序,String.CASE_INSENSITIVE_ORDER
實現比較器忽視大小寫,像String內部有比較器。
倒過來排序,實現Comparator比較器就可以,compare()返回int類型,方法參數o1是第一個對象,o2第二個對象交換對象。默認去重複,如果想不去重複,比較器可以改
更簡單的用法,調用Collections靜態方法排序
//正序
Map<String, String> map = new TreeMap<>(Collections.reverseOrder());
//倒序
// Map<String, String> map = new TreeMap<>(
// Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
map.put("4", "李");
map.put("4", "波");
map.put("3", "勇");
map.put("2", "22");
for (Map.Entry<String, String> kv : map.entrySet()) {
System.out.print("鍵:"+kv.getKey() + "=" + "值:"+kv.getValue()+"|");
}
重寫比較器按時間排序,不是字符串排序
實現原理大致是
紅黑樹可看做平衡排序二叉樹,
//比較器是構造方法傳過來的,沒傳默認null
private final Comparator<? super K> comparator;
//指向樹的根節點,下面Entry
private transient Entry<K,V> root;
private transient int size = 0;
/**
* The number of structural modifications to the tree.
* 樹的結構修改數
*/
private transient int modCount = 0;
這靜態內部類Entry由外部root對象引用。由根節點訪問下面每一個節點Entry
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
//節點引用左邊
Entry<K,V> left;
//節點引用右邊
Entry<K,V> right;
//父節點
Entry<K,V> parent;
//節點顏色,默認根節點是黑色
boolean color = BLACK;
/**
* Make a new cell with given key, value, and parent, and with
* {@code null} child links, and BLACK color.
*/
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
put()添加方法,首先添加前compare()檢查key的類型和null。第一次添加判斷是null創建Entry節點,指向root根節點
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;
}
添加方法下面根據比較器comparator
和Comparable
來區分保存值,默認指向父節點,從父節點比較輸入的key 和 引用key,小於根節點,將t節點設置左,大於根節點將t設置到右邊。setValue()有重複的值,設置返回。循環結束t = null 。
//保存比較結果
int cmp;
//父節點
Entry<K,V> parent;
//比較器
Comparator<? super K> cpr = comparator;
if (cpr != null) { //實現比較器Comparator
do {
//開始t節點指向父節點
parent = t;
//從根節點比較鍵
cmp = cpr.compare(key, t.key);
//小於根節點,將t設置左邊
if (cmp < 0)
t = t.left;
//大於根節點,將t設置到右邊
else if (cmp > 0)
t = t.right;
else
//比較有這個鍵返回設置值
return t.setValue(value);
//t null退出循環
} while (t != null);
}
else { //Comparable實現比較器
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
//compareTo比較
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);
}
//上面步驟找到父節點後,就是新建一個節點,k / v 根
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;
}
get()方法根據鍵獲取值,通過p找到值value
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
containsValue()方法根據值獲取通過for循環,找到返回true,valEquals比較裏面是equals
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;
}
remove()刪除方法。底層deleteEntry()方法刪除鍵,刪除修改指向,給賦nul,l分爲左和右以及根節點。
public V remove(Object key) {
Entry<K,V> p = getEntry(key);
if (p == null)
return null;
V oldValue = p.value;
deleteEntry(p); //重要方法
return oldValue;
}