HashMap 之元素刪除

微信公衆號:I am CR7
若有問題或建議,請在下方留言;
最近更新:2018-09-18java

HashMap之元素刪除

     繼上一篇HashMap之元素插入,咱們繼續來看下元素刪除的實現原理。node

一、源碼:
1public V remove(Object key) {
2    Node<K,V> e;
3    return (e = removeNode(hash(key), key, nullfalsetrue)) == null ?
4        null : e.value;
5}
複製代碼

看下核心方法removeNode:數組

 1//matchValue爲false 表示不須要比對value值一致
2//movable爲false 表示刪除節點後不移動其餘節點
3final Node<K,V> removeNode(int hash, Object key, Object value,
4                           boolean matchValue, boolean movable)
 
{
5    //p爲當前檢查的節點
6    Node<K,V>[] tab; Node<K,V> p; int n, index;
7    if ((tab = table) != null && (n = tab.length) > 0 &&
8        (p = tab[index = (n - 1) & hash]) != null) { //待刪除節點在數組索引位置存在元素
9        //node爲找到的刪除節點
10        Node<K,V> node = null, e; K k; V v;
11        if (p.hash == hash &&
12            ((k = p.key) == key || (key != null && key.equals(k))))//哈希值一致,key一致則找到了要刪除的節點
13            node = p;
14        else if ((e = p.next) != null) {//未找到則看後繼節點
15            if (p instanceof TreeNode)//若是後繼節點爲紅黑樹節點,則在紅黑樹中查找要刪除的節點
16                node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
17            else {
18                do {
19                    if (e.hash == hash &&
20                        ((k = e.key) == key ||
21                         (key != null && key.equals(k)))) {
22                        node = e;
23                        break;
24                    }
25                    p = e;
26                } while ((e = e.next) != null);//不爲紅黑樹節點,則遍歷單鏈表查找
27            }
28        }
29        if (node != null && (!matchValue || (v = node.value) == value ||
30                             (value != null && value.equals(v)))) {//找到節點,matchValue爲true,還須要比對value值
31            if (node instanceof TreeNode)
32                ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);//待刪除節點爲紅黑樹節點,則進行紅黑樹節點的刪除操做
33            else if (node == p)//待刪除節點爲數組中的元素,直接將後繼節點替換便可
34                tab[index] = node.next;
35            else//待刪除節點爲單鏈表中的元素,將後繼節點做爲前驅節點的後繼節點便可
36                p.next = node.next;
37            ++modCount;
38            --size;
39            afterNodeRemoval(node);
40            return node;
41        }
42    }
43    return null;
44}
複製代碼

二、流程圖:

圖注:刪除元素流程圖
刪除元素流程圖

三、說明:

     由於HashMap存在三種存儲方式,數組、單鏈表、紅黑樹,那麼刪除元素時必然存在着這三種狀況。其中,紅黑樹的刪除最爲複雜,我們接着往下看。微信

紅黑樹之查找元素

一、源碼:

 1final TreeNode<K,V> getTreeNode(int h, Object k) {
2    return ((parent != null) ? root() : this).find(h, k, null);
3}
4
5//查找紅黑樹的根節點
6final TreeNode<K,V> root() {
7    for (TreeNode<K,V> r = this, p;;) {
8        if ((p = r.parent) == null)
9            return r;
10        r = p;
11    }
12}
13
14//遍歷紅黑樹查找指定哈希和key的節點
15final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
16    TreeNode<K,V> p = this;
17    do {
18        int ph, dir; K pk;
19        TreeNode<K,V> pl = p.left, pr = p.right, q;//保存左節點 右節點 
20        if ((ph = p.hash) > h) //左節點哈希值大於給定查找節點的哈希值,則繼續往左找
21            p = pl;
22        else if (ph < h)//左節點哈希值小於給定查找節點的哈希值,則往右找
23            p = pr;
24        else if ((pk = p.key) == k || (k != null && k.equals(pk)))//當前節點key值一致,則返回該節點
25            return p;
26        else if (pl == null)//左節點爲空,則往右找
27            p = pr;
28        else if (pr == null)//右節點爲空,則往左找
29            p = pl;
30        else if ((kc != null ||//哈希相同,key不一樣,且有左右節點。此時看key是否可比較,是則比較key值
31                  (kc = comparableClassFor(k)) != null) &&
32                 (dir = compareComparables(kc, k, pk)) != 0)
33            p = (dir < 0) ? pl : pr;//小於往左,大於往右
34        else if ((q = pr.find(h, k, kc)) != null)//哈希相同,key不可比或者key也相同,則往右查找
35            return q;
36        else//不然往左
37            p = pl;
38    } while (p != null);
39    return null;
40}
複製代碼

二、流程圖:

圖注:查找元素流程圖
查找元素流程圖

紅黑樹之刪除元素

一、源碼:

 1final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
2                          boolean movable)
 
{
3    int n;
4    if (tab == null || (n = tab.length) == 0)
5        return;
6    int index = (n - 1) & hash;
7    TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
8    TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
9    if (pred == null//待刪除節點爲根節點,則其後繼節點做爲數組索引位置的元素
10        tab[index] = first = succ;
11    else//待刪除節點存在前驅節點,則後繼節點做爲前驅節點的下一個節點
12        pred.next = succ;
13    if (succ != null)//待刪除節點存在後繼節點,則前驅節點做爲後繼節點的上一個節點
14        succ.prev = pred;
15    if (first == null)//數組索引位置元素爲null,直接返回
16        return;
17    if (root.parent != null)//找到紅黑樹的根節點
18        root = root.root();
19    if (root == null || root.right == null ||
20        (rl = root.left) == null || rl.left == null) {//紅黑樹過小則進行去樹化操做
21        tab[index] = first.untreeify(map);  // too small
22        return;
23    }
24    //查找替代節點replacement
25    //p爲待刪除節點,pl爲其左節點,pr爲其右節點,replacement爲替代節點
26    TreeNode<K,V> p = this, pl = left, pr = right, replacement;
27    if (pl != null && pr != null) {//待刪除節點有左右節點
28       //s爲後繼節點 
29TreeNode<K,V> s = pr, sl;
30        while ((sl = s.left) != null)//往待刪除節點右子樹的左邊走 
31            s = sl;
32        boolean c = s.red; s.red = p.red; p.red = c;//互換後繼節點和待刪除節點的顏色
33        //sr爲後繼節點的右節點
34        TreeNode<K,V> sr = s.right;
35        //pp爲待刪除節點的父節點
36        TreeNode<K,V> pp = p.parent;
37        if (s == pr) {//待刪除節點的右節點無左孩子--->右節點和待刪除節點互換
38            p.parent = s;
39            s.right = p;
40        }
41        else {//待刪除節點的右節點有左孩子
42            //sp爲後繼節點的父節點
43            TreeNode<K,V> sp = s.parent;
44            //後繼節點存在父節點,則讓待刪除節點替代後繼節點
45            if ((p.parent = sp) != null) {//後繼節點的父節點成爲待刪除節點的父節點
46                if (s == sp.left)//後繼節點爲其父節點的左孩子
47                    sp.left = p;//待刪除節點就做爲後繼節點的父節點的左孩子
48                else
49                    sp.right = p;//待刪除節點就做爲後繼節點的父節點的右孩子
50            }
51            //待刪除節點存在右節點,則讓後繼節點成爲其父節點
52            if ((s.right = pr) != null)
53                pr.parent = s;
54        }
55        p.left = null;//待刪除節點左孩子爲null
56        if ((p.right = sr) != null)//後繼節點存在右節點,則讓其成爲待刪除節點的右節點
57            sr.parent = p;//相對應,待刪除節點成爲其父節點
58        if ((s.left = pl) != null)//待刪除節點存在左節點,則讓其成爲後繼節點的左節點
59            pl.parent = s;//相對應,後繼節點成爲其父節點
60        //待刪除節點存在父節點,則讓後繼節點替代待刪除節點
61        if ((s.parent = pp) == null)//待刪除節點不存在父節點,則後繼節點父節點爲null
62            root = s;//後繼節點成爲根節點
63        else if (p == pp.left)//待刪除節點存在父節點,且待刪除節點是其左節點
64            pp.left = s;//後繼節點做爲其左節點
65        else
66            pp.right = s;//後繼節點做爲其右節點
67        //後繼節點存在右節點,則替代節點爲該節點
68        if (sr != null)
69            replacement = sr;
70        else //替代節點爲待刪除節點(等於未找到)
71            replacement = p;
72    }
73    else if (pl != null)//待刪除節點只有左節點
74        replacement = pl;
75    else if (pr != null)//待刪除節點只有右節點
76        replacement = pr;
77    else//待刪除節點爲葉子節點
78        replacement = p;
79    if (replacement != p) {//替代節點不爲待刪除節點,則先進行節點刪除,而後進行平衡調整
80        TreeNode<K,V> pp = replacement.parent = p.parent;
81        if (pp == null)
82            root = replacement;
83        else if (p == pp.left)
84            pp.left = replacement;
85        else
86            pp.right = replacement;
87        p.left = p.right = p.parent = null;
88    }
89
90    TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);//進行平衡調整
91
92    if (replacement == p) {  //替代節點爲待刪除節點,則先進行平衡調整,而後進行節點刪除
93        TreeNode<K,V> pp = p.parent;
94        p.parent = null;
95        if (pp != null) {
96            if (p == pp.left)
97                pp.left = null;
98            else if (p == pp.right)
99                pp.right = null;
100        }
101    }
102    if (movable)//將紅黑樹根節點移動到數組索引位置
103        moveRootToFront(tab, r);
104}
複製代碼

二、流程圖:

圖注:刪除元素流程圖
刪除元素流程圖

三、說明:

     以上爲HashMap的紅黑樹刪除流程,其實思路和TreeMap中紅黑樹大體相同,關於TreeMap的解析,請看TreeMap之元素刪除,文章中我對紅黑樹的刪除過程進行了詳細的分析,這裏就不作詳細闡述了。app

示例

     咱們經過一個具體的例子,來體會下刪除的過程,請看:
this

圖注:初始狀態
初始狀態

圖注:刪除10
刪除10

圖注:刪除226
刪除226

圖注:刪除320
刪除320

圖注:替代刪除
替代刪除

圖注:平衡調整
平衡調整

圖注:刪除384
刪除384

圖注:平衡調整
平衡調整

圖注:刪除
刪除

圖注:刪除0
刪除0

圖注:平衡調整
平衡調整

圖注:平衡調整
平衡調整

圖注:刪除
刪除

圖注:刪除64
刪除64

圖注:刪除
刪除

圖注:刪除128
刪除128

圖注:平衡調整
平衡調整

圖注:平衡調整
圖注:平衡調整

圖注:刪除
刪除

圖注:刪除512
刪除512

圖注:去樹化
去樹化

總結

     經過上述的分析,結合着TreeMap之元素刪除這篇文章,我想,要理解HashMap的刪除,並非一件難事。
     文章的最後,感謝你們的支持,歡迎掃描下方二維碼,進行關注。若有任何疑問,歡迎你們留言。spa

相關文章
相關標籤/搜索