溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

JDK的TreeMap怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-31 16:00:30 來(lái)源:億速云 閱讀:138 作者:iii 欄目:編程語(yǔ)言

這篇文章主要講解了“JDK的TreeMap怎么實(shí)現(xiàn)”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“JDK的TreeMap怎么實(shí)現(xiàn)”吧!

TreeMap的實(shí)現(xiàn)也是利用的紅黑樹(shù),我們來(lái)看代碼:

在TreeMap中包含著一個(gè)根結(jié)點(diǎn):

  1. private transient Entry<K,V> root = null;

這個(gè)Entry代碼如下:

  1. static final class Entry<K,V> implements Map.Entry<K,V> {

  2.         K key;

  3.         V value;

  4.         //指向小兒子

  5.         Entry<K,V> left = null;

  6.         //指向大兒子

  7.         Entry<K,V> right = null;

  8.          //指向父親

  9.         Entry<K,V> parent;

  10.         //顏色默認(rèn)為黑色

  11.         boolean color = BLACK;


  12.         Entry(K key, V value, Entry<K,V> parent) {

  13.             this.key = key;

  14.             this.value = value;

  15.             this.parent = parent;

  16.         }


  17.         public K getKey() {

  18.             return key;

  19.         }



  20.         public V getValue() {

  21.             return value;

  22.         }



  23.         public V setValue(V value) {

  24.             V oldValue = this.value;

  25.             this.value = value;

  26.             return oldValue;

  27.         }


  28.         public boolean equals(Object o) {

  29.             if (!(o instanceof Map.Entry))

  30.                 return false;

  31.             Map.Entry<?,?> e = (Map.Entry<?,?>)o;


  32.             return valEquals(key,e.getKey()) && valEquals(value,e.getValue());

  33.         }


  34.         public int hashCode() {

  35.             int keyHash = (key==null ? 0 : key.hashCode());

  36.             int valueHash = (value==null ? 0 : value.hashCode());

  37.             return keyHash ^ valueHash;

  38.         }


  39.         public String toString() {

  40.             return key + "=" + value;

  41.         }

  42.     }

廢話不多說(shuō),我們來(lái)看一下他的插入實(shí)現(xiàn):

  1.  public V put(K key, V value) {

  2.         Entry<K,V> t = root;

  3.         //如果樹(shù)是空樹(shù)

  4.         if (t == null) {

  5.             //那么樹(shù)根節(jié)點(diǎn)就是節(jié)點(diǎn)

  6.             root = new Entry<K,V>(key, value, null);

  7.             size = 1;

  8.             modCount++;

  9.             return null;

  10.         }

  11.         int cmp;

  12.         Entry<K,V> parent;

  13.         //否則利用提供的比較器進(jìn)行比較

  14.         Comparator<? super K> cpr = comparator;

  15.         if (cpr != null) {

  16.             do {

  17.                 parent = t; 


  18.                 cmp = cpr.compare(key, t.key);

  19.                 //如果比當(dāng)前節(jié)點(diǎn)小,

  20.                 if (cmp < 0)

  21.                     //往小兒子遞歸

  22.                     t = t.left;

  23.                 else if (cmp > 0)

  24.                     //往大兒子遞歸

  25.                     t = t.right;

  26.                 else

  27.                     //如果已經(jīng)有這個(gè)key,那么修改key,并且什么都可以 不修改了

  28.                     return t.setValue(value);

  29.             } while (t != null); //知道找到葉子節(jié)點(diǎn);

  30.         }

  31.         else {

  32.             if (key == null)

  33.                 throw new NullPointerException();

  34.             //如果沒(méi)有提供外部的比較器,那么就利用內(nèi)置的比較器

  35.             Comparable<? super K> k = (Comparable<? super K>) key;

  36.             do {

  37.                 parent = t;

  38.                 cmp = k.compareTo(t.key);

  39.                 if (cmp < 0)

  40.                     t = t.left;

  41.                 else if (cmp > 0)

  42.                     t = t.right;

  43.                 else

  44.                     return t.setValue(value);

  45.             } while (t != null);

  46.         }

  47.         //生成一個(gè)葉子節(jié)點(diǎn),準(zhǔn)備進(jìn)行加入

  48.         Entry<K,V> e = new Entry<K,V>(key, value, parent);

  49.         //利用最后的判斷,將這個(gè)節(jié)點(diǎn)變成該葉子節(jié)點(diǎn)的兒子;

  50.         if (cmp < 0)

  51.             parent.left = e;

  52.         else

  53.             parent.right = e;

  54.         //由于有可能破壞了紅黑樹(shù)的規(guī)則,現(xiàn)在進(jìn)行調(diào)整;

  55.         fixAfterInsertion(e);

  56.         size++;

  57.         modCount++;

  58.         return null;

  59.     }



  1. private void fixAfterInsertion(Entry<K,V> x) {

  2.         //首先將該新增節(jié)點(diǎn)染紅,葉子節(jié)點(diǎn)(null)是黑色的;

  3.         x.color = RED;

  4.         //如果他的父親是紅色的,那么沖突開(kāi)始;

  5.         while (x != null && x != root && x.parent.color == RED) {

  6.             //如果是左子數(shù);

  7.             if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {

  8.                 Entry<K,V> y = rightOf(parentOf(parentOf(x)));

  9.                 //如果其兄弟是紅色的,那么根據(jù)上一節(jié)的分析,將兩兄弟都變成黑色,其父節(jié)點(diǎn)變紅,這樣黑色節(jié)點(diǎn)的數(shù)目沒(méi)有發(fā)生變化,而我們距離跟更近一步;

  10.                 if (colorOf(y) == RED) {

  11.                     setColor(parentOf(x), BLACK);

  12.                     setColor(y, BLACK);

  13.                     setColor(parentOf(parentOf(x)), RED);

  14.                     x = parentOf(parentOf(x));

  15.                 } else {

  16.                  //兄弟為黑色


  17.                     if (x == rightOf(parentOf(x))) {

  18.                         x = parentOf(x);

  19.                         rotateLeft(x);

  20.                     }

  21.                     setColor(parentOf(x), BLACK);

  22.                     setColor(parentOf(parentOf(x)), RED);

  23.                     rotateRight(parentOf(parentOf(x)));

  24.                 }

  25.                //如果是右子數(shù),正好與上面相反;

  26.             } else {

  27.                 Entry<K,V> y = leftOf(parentOf(parentOf(x)));

  28.                 if (colorOf(y) == RED) {

  29.                     setColor(parentOf(x), BLACK);

  30.                     setColor(y, BLACK);

  31.                     setColor(parentOf(parentOf(x)), RED);

  32.                     x = parentOf(parentOf(x));

  33.                 } else {

  34.                     if (x == leftOf(parentOf(x))) {

  35.                         x = parentOf(x);

  36.                         rotateRight(x);

  37.                     }

  38.                     setColor(parentOf(x), BLACK);

  39.                     setColor(parentOf(parentOf(x)), RED);

  40.                     rotateLeft(parentOf(parentOf(x)));

  41.                 }

  42.             }

  43.         }

  44.         //沖突會(huì)一直追溯到跟,把跟染黑,不違背根節(jié)點(diǎn)是黑色的特性,并且使得所有的樹(shù)枝的黑色節(jié)點(diǎn)因此加1,沖突解決;

  45.         root.color = BLACK;

  46.     }


看完了增加,我們?cè)賮?lái)看看刪除

  1.   public V remove(Object key) {

  2.         //查找到該節(jié)點(diǎn)

  3.         Entry<K,V> p = getEntry(key);

  4.         //不存在則結(jié)束

  5.         if (p == null)

  6.             return null;


  7.         V oldValue = p.value;

  8.         //刪除

  9.         deleteEntry(p);

  10.         //返回原值

  11.         return oldValue;

  12.     }

查找該節(jié)點(diǎn):

  1. final Entry<K,V> getEntry(Object key) {

  2.         if (comparator != null)

  3.             //利用外部比較器

  4.             return getEntryUsingComparator(key);

  5.         if (key == null)

  6.             throw new NullPointerException();

  7.         //內(nèi)置比較器

  8.     Comparable<? super K> k = (Comparable<? super K>) key;

  9.         Entry<K,V> p = root;

  10.         while (p != null) {

  11.             int cmp = k.compareTo(p.key);

  12.             if (cmp < 0)

  13.                 p = p.left;

  14.             else if (cmp > 0)

  15.                 p = p.right;

  16.             else

  17.                 return p;

  18.         }

  19.         return null;

  20.     }

外部比較器查找節(jié)點(diǎn):

  1.     final Entry<K,V> getEntryUsingComparator(Object key) {

  2.     K k = (K) key;

  3.         Comparator<? super K> cpr = comparator;

  4.         if (cpr != null) {

  5.             Entry<K,V> p = root;

  6.             while (p != null) {

  7.                 int cmp = cpr.compare(k, p.key);

  8.                 if (cmp < 0)

  9.                     p = p.left;

  10.                 else if (cmp > 0)

  11.                     p = p.right;

  12.                 else

  13.                     return p;

  14.             }

  15.         }

  16.         return null;

  17.     }

刪除操作:

  1.   private void deleteEntry(Entry<K,V> p) {

  2.         modCount++;

  3.         size--;

  4.         //如果刪除的節(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn);

  5.         if (p.left != null && p.right != null) {

  6.             Entry<K,V> s = successor (p);

  7.             p.key = s.key;

  8.             p.value = s.value;

  9.             p = s;

  10.         } 


  11.         //兩個(gè)子節(jié)點(diǎn)的刪除轉(zhuǎn)化為了一個(gè)子節(jié)點(diǎn)的刪除

  12.        //進(jìn)行一個(gè)子節(jié)點(diǎn)的刪除操作;

  13.         Entry<K,V> replacement = (p.left != null ? p.left : p.right);


  14.        //如果有一個(gè)以上的節(jié)點(diǎn);重新接上樹(shù)枝; 

  15.         if (replacement != null) {


  16.             replacement.parent = p.parent;

  17.             if (p.parent == null)

  18.                 root = replacement;

  19.             else if (p == p.parent.left)

  20.                 p.parent.left  = replacement;

  21.             else

  22.                 p.parent.right = replacement;


  23.             p.left = p.right = p.parent = null;

  24.             //如果刪除位置的新節(jié)點(diǎn)是黑色的,那么會(huì)少一個(gè)黑節(jié)點(diǎn),調(diào)整

  25.             if (p.color == BLACK)

  26.             //調(diào)整新的節(jié)點(diǎn),即刪除節(jié)點(diǎn)的子節(jié)點(diǎn);

  27.                 fixAfterDeletion(replacement);

  28.         } else if (p.parent == null) { // return if we are the only node.

  29.             root = null;

  30.         } else {  

  31.             //如果沒(méi)有子節(jié)點(diǎn)

  32.             //紅色的節(jié)點(diǎn)要可以直接刪除,黑色的話,必須要經(jīng)過(guò)調(diào)整;

  33.             if (p.color == BLACK)

  34.                 fixAfterDeletion(p);

  35.            //刪除操作;

  36.             if (p.parent != null) {

  37.                 if (p == p.parent.left)

  38.                     p.parent.left = null;

  39.                 else if (p == p.parent.right)

  40.                     p.parent.right = null;

  41.                 p.parent = null;

  42.             }

  43.         }

  44.     }

刪除后的調(diào)整:

  1. private void fixAfterDeletion(Entry<K,V> x) {

  2.         // 如果節(jié)點(diǎn)是黑色的;那么要經(jīng)過(guò)調(diào)整,如果是紅色的,可以直接修改成為黑色的,結(jié)束循環(huán);

  3.         while (x != root && colorOf(x) == BLACK)

  4.             // 判斷被刪除節(jié)點(diǎn)是左子樹(shù);

  5.             if (x == leftOf(parentOf(x))) {

  6.                 // 獲得兄弟節(jié)點(diǎn);

  7.                 Entry<K,V> sib = rightOf(parentOf(x));

  8.                 //兄弟節(jié)點(diǎn)是紅色的


  9.                 if (colorOf(sib) == RED) {

  10.                     setColor(sib, BLACK);

  11.                     setColor(parentOf(x), RED);

  12.                     //開(kāi)始旋轉(zhuǎn)

  13.                     rotateLeft(parentOf(x));

  14.                     // 得到旋轉(zhuǎn)后的新的兄弟節(jié)點(diǎn);這個(gè)時(shí)候是黑色的

  15.                     sib = rightOf(parentOf(x));

  16.                 }

  17.                 //判斷侄子的顏色;如果兩個(gè)都是黑色的


  18.                 if (colorOf(leftOf(sib))  == BLACK &&

  19.                     colorOf(rightOf(sib)) == BLACK) {

  20.                     setColor(sib, RED);

  21.                     x = parentOf(x);

  22.                 } else {

  23.                     // 只有一個(gè)是黑色的

  24.                    // 如果是黑色的那個(gè)侄子位置不對(duì),那么經(jīng)過(guò)一次轉(zhuǎn)換;

  25.                     if (colorOf(rightOf(sib)) == BLACK) {

  26.                         setColor(leftOf(sib), BLACK);

  27.                         setColor(sib, RED);

  28.                         rotateRight(sib);

  29.                         sib = rightOf(parentOf(x));

  30.                     }

  31.                     setColor(sib, colorOf(parentOf(x)));

  32.                     setColor(parentOf(x), BLACK);

  33.                     setColor(rightOf(sib), BLACK);

  34.                     rotateLeft(parentOf(x));

  35.                     x = root;

  36.                 }

  37.             } else {

  38.                 Entry<K,V> sib = leftOf(parentOf(x));


  39.                 if (colorOf(sib) == RED) {

  40.                     setColor(sib, BLACK);

  41.                     setColor(parentOf(x), RED);

  42.                     rotateRight(parentOf(x));

  43.                     sib = leftOf(parentOf(x));

  44.                 }


  45.                 if (colorOf(rightOf(sib)) == BLACK &&

  46.                     colorOf(leftOf(sib)) == BLACK) {

  47.                     setColor(sib, RED);

  48.                     x = parentOf(x);

  49.                 } else {

  50.                     if (colorOf(leftOf(sib)) == BLACK) {

  51.                         setColor(rightOf(sib), BLACK);

  52.                         setColor(sib, RED);

  53.                         rotateLeft(sib);

  54.                         sib = leftOf(parentOf(x));

  55.                     }

  56.                     setColor(sib, colorOf(parentOf(x)));

  57.                     setColor(parentOf(x), BLACK);

  58.                     setColor(leftOf(sib), BLACK);

  59.                     rotateRight(parentOf(x));

  60.                     x = root;

  61.                 }

  62.             }

  63.         }

  64.         //如果該節(jié)點(diǎn)不是黑色的,或者是根節(jié)點(diǎn),那么把他染黑;

  65.         setColor(x, BLACK);

  66.     }

  1.  static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {

  2.         //如果為null,則返回

  3.         if (t == null)

  4.             return null;

  5.         //如果大兒子存在,那么沿著這條路下去,找到其這個(gè)枝條中最小的節(jié)點(diǎn)

  6.         else if (t.right != null) {

  7.             Entry<K,V> p = t.right;

  8.             while (p.left != null)

  9.                 p = p.left;

  10.             return p;

  11.         } else {

  12.         //如果右邊子樹(shù)是空的,那么找到其長(zhǎng)輩節(jié)點(diǎn)中間第一個(gè)大于他的

  13.             Entry<K,V> p = t.parent;

  14.             Entry<K,V> ch = t;

  15.             while (p != null && ch == p.right) {

  16.                 ch = p;

  17.                 p = p.parent;

  18.             }

  19.             return p;

  20.         }

  21.     }

我們?cè)賮?lái)看一下我們?cè)讷@取其集合的時(shí)候的順序:

  1.    static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {

  2.         private final NavigableMap<E, Object> m;

  3.         KeySet(NavigableMap<E,Object> map) { m = map; }


  4.         public Iterator<E> iterator() {

  5.             if (m instanceof TreeMap)

  6.                 return ((TreeMap<E,Object>)m).keyIterator();

  7.             else

  8.                 return (Iterator<E>)(((TreeMap.NavigableSubMap)m).keyIterator());

  9.         }


  10.         public Iterator<E> descendingIterator() {

  11.             if (m instanceof TreeMap)

  12.                 return ((TreeMap<E,Object>)m).descendingKeyIterator();

  13.             else

  14.                 return (Iterator<E>)(((TreeMap.NavigableSubMap)m).descendingKeyIterator());

  15.         }


  16.         public int size() { return m.size(); }

  17.         public boolean isEmpty() { return m.isEmpty(); }

  18.         public boolean contains(Object o) { return m.containsKey(o); }

  19.         public void clear() { m.clear(); }

  20.         public E lower(E e) { return m.lowerKey(e); }

  21.         public E floor(E e) { return m.floorKey(e); }

  22.         public E ceiling(E e) { return m.ceilingKey(e); }

  23.         public E higher(E e) { return m.higherKey(e); }

  24.         public E first() { return m.firstKey(); }

  25.         public E last() { return m.lastKey(); }

  26.         public Comparator<? super E> comparator() { return m.comparator(); }

  27.         public E pollFirst() {

  28.             Map.Entry<E,Object> e = m.pollFirstEntry();

  29.             return e == nullnull : e.getKey();

  30.         }

  31.         public E pollLast() {

  32.             Map.Entry<E,Object> e = m.pollLastEntry();

  33.             return e == nullnull : e.getKey();

  34.         }

  35.         public boolean remove(Object o) {

  36.             int oldSize = size();

  37.             m.remove(o);

  38.             return size() != oldSize;

  39.         }

  40.         public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,

  41.                                       E toElement,   boolean toInclusive) {

  42.             return new TreeSet<E>(m.subMap(fromElement, fromInclusive,

  43.                                            toElement,   toInclusive));

  44.         }

  45.         public NavigableSet<E> headSet(E toElement, boolean inclusive) {

  46.             return new TreeSet<E>(m.headMap(toElement, inclusive));

  47.         }

  48.         public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {

  49.             return new TreeSet<E>(m.tailMap(fromElement, inclusive));

  50.         }

  51.         public SortedSet<E> subSet(E fromElement, E toElement) {

  52.             return subSet(fromElement, true, toElement, false);

  53.         }

  54.         public SortedSet<E> headSet(E toElement) {

  55.             return headSet(toElement, false);

  56.         }

  57.         public SortedSet<E> tailSet(E fromElement) {

  58.             return tailSet(fromElement, true);

  59.         }

  60.         public NavigableSet<E> descendingSet() {

  61.             return new TreeSet(m.descendingMap());

  62.         }

  63.     }

這個(gè)是返回的set,他的查找排序是利用的迭代模式委托給了迭代器,我們看看他的迭代器實(shí)現(xiàn):

  1.  final class KeyIterator extends PrivateEntryIterator<K> {

  2.         KeyIterator(Entry<K,V> first) {

  3.             super(first);

  4.         }

  5.         public K next() {

  6.             return nextEntry().key;

  7.         }

  8.     }

其中獲取下一個(gè)nextEntry是:

  1. final Entry<K,V> nextEntry() {

  2.             Entry<K,V> e = next;

  3.             if (e == null)

  4.                 throw new NoSuchElementException();

  5.             if (modCount != expectedModCount)

  6.                 throw new ConcurrentModificationException();

  7.             next = successor(e);

  8.             lastReturned = e;

  9.             return e;

  10.         }

利用的successvor(),在開(kāi)始的分析中我們知道,successor的查找,是通過(guò)了樹(shù)的中序遍歷的

感謝各位的閱讀,以上就是“JDK的TreeMap怎么實(shí)現(xiàn)”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)JDK的TreeMap怎么實(shí)現(xiàn)這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI