网站建设资讯

NEWS

网站建设资讯

JDK的TreeMap怎么实现-创新互联

这篇文章主要讲解了“JDK的TreeMap怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JDK的TreeMap怎么实现”吧!

创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站建设、成都做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的东乌珠穆沁网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!

TreeMap的实现也是利用的红黑树,我们来看代码:

在TreeMap中包含着一个根结点:

  1. private transient Entry root = null;

这个Entry代码如下:

  1. static final class Entry implements Map.Entry {

  2.         K key;

  3.         V value;

  4.         //指向小儿子

  5.         Entry left = null;

  6.         //指向大儿子

  7.         Entry right = null;

  8.          //指向父亲

  9.         Entry parent;

  10.         //颜色默认为黑色

  11.         boolean color = BLACK;


  12.         Entry(K key, V value, Entry 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.     }

废话不多说,我们来看一下他的插入实现:

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

  2.         Entry t = root;

  3.         //如果树是空树

  4.         if (t == null) {

  5.             //那么树根节点就是节点

  6.             root = new Entry(key, value, null);

  7.             size = 1;

  8.             modCount++;

  9.             return null;

  10.         }

  11.         int cmp;

  12.         Entry parent;

  13.         //否则利用提供的比较器进行比较

  14.         Comparator cpr = comparator;

  15.         if (cpr != null) {

  16.             do {

  17.                 parent = t;


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

  19.                 //如果比当前节点小,

  20.                 if (cmp < 0)

  21.                     //往小儿子递归

  22.                     t = t.left;

  23.                 else if (cmp > 0)

  24.                     //往大儿子递归

  25.                     t = t.right;

  26.                 else

  27.                     //如果已经有这个key,那么修改key,并且什么都可以 不修改了

  28.                     return t.setValue(value);

  29.             } while (t != null); //知道找到叶子节点;

  30.         }

  31.         else {

  32.             if (key == null)

  33.                 throw new NullPointerException();

  34.             //如果没有提供外部的比较器,那么就利用内置的比较器

  35.             Comparable k = (Comparable) 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.         //生成一个叶子节点,准备进行加入

  48.         Entry e = new Entry(key, value, parent);

  49.         //利用最后的判断,将这个节点变成该叶子节点的儿子;

  50.         if (cmp < 0)

  51.             parent.left = e;

  52.         else

  53.             parent.right = e;

  54.         //由于有可能破坏了红黑树的规则,现在进行调整;

  55.         fixAfterInsertion(e);

  56.         size++;

  57.         modCount++;

  58.         return null;

  59.     }



  1. private void fixAfterInsertion(Entry x) {

  2.         //首先将该新增节点染红,叶子节点(null)是黑色的;

  3.         x.color = RED;

  4.         //如果他的父亲是红色的,那么冲突开始;

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

  6.             //如果是左子数;

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

  8.                 Entry y = rightOf(parentOf(parentOf(x)));

  9.                 //如果其兄弟是红色的,那么根据上一节的分析,将两兄弟都变成黑色,其父节点变红,这样黑色节点的数目没有发生变化,而我们距离跟更近一步;

  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.                //如果是右子数,正好与上面相反;

  26.             } else {

  27.                 Entry 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.         //冲突会一直追溯到跟,把跟染黑,不违背根节点是黑色的特性,并且使得所有的树枝的黑色节点因此加1,冲突解决;

  45.         root.color = BLACK;

  46.     }


看完了增加,我们再来看看删除

  1.   public V remove(Object key) {

  2.         //查找到该节点

  3.         Entry p = getEntry(key);

  4.         //不存在则结束

  5.         if (p == null)

  6.             return null;


  7.         V oldValue = p.value;

  8.         //删除

  9.         deleteEntry(p);

  10.         //返回原值

  11.         return oldValue;

  12.     }

查找该节点:

  1. final Entry getEntry(Object key) {

  2.         if (comparator != null)

  3.             //利用外部比较器

  4.             return getEntryUsingComparator(key);

  5.         if (key == null)

  6.             throw new NullPointerException();

  7.         //内置比较器

  8.     Comparable k = (Comparable) key;

  9.         Entry 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.     }

外部比较器查找节点:

  1.     final Entry getEntryUsingComparator(Object key) {

  2.     K k = (K) key;

  3.         Comparator cpr = comparator;

  4.         if (cpr != null) {

  5.             Entry 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 p) {

  2.         modCount++;

  3.         size--;

  4.         //如果删除的节点有两个子节点;

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

  6.             Entry s = successor (p);

  7.             p.key = s.key;

  8.             p.value = s.value;

  9.             p = s;

  10.         }


  11.         //两个子节点的删除转化为了一个子节点的删除

  12.        //进行一个子节点的删除操作;

  13.         Entry replacement = (p.left != null ? p.left : p.right);


  14.        //如果有一个以上的节点;重新接上树枝;

  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.             //如果删除位置的新节点是黑色的,那么会少一个黑节点,调整

  25.             if (p.color == BLACK)

  26.             //调整新的节点,即删除节点的子节点;

  27.                 fixAfterDeletion(replacement);

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

  29.             root = null;

  30.         } else {

  31.             //如果没有子节点

  32.             //红色的节点要可以直接删除,黑色的话,必须要经过调整;


  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.     }

删除后的调整:

  1. private void fixAfterDeletion(Entry x) {

  2.         // 如果节点是黑色的;那么要经过调整,如果是红色的,可以直接修改成为黑色的,结束循环;


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

  4.             // 判断被删除节点是左子树;


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

  6.                 // 获得兄弟节点;

  7.                 Entry sib = rightOf(parentOf(x));

  8.                 //兄弟节点是红色的



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

  10.                     setColor(sib, BLACK);

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

  12.                     //开始旋转


  13.                     rotateLeft(parentOf(x));

  14.                     // 得到旋转后的新的兄弟节点;这个时候是黑色的


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

  16.                 }

  17.                 //判断侄子的颜色;如果两个都是黑色的



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

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

  20.                     setColor(sib, RED);

  21.                     x = parentOf(x);

  22.                 } else {

  23.                     // 只有一个是黑色的

  24.                    // 如果是黑色的那个侄子位置不对,那么经过一次转换;


  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 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.         //如果该节点不是黑色的,或者是根节点,那么把他染黑;

  65.         setColor(x, BLACK);

  66.     }

  1.  static  TreeMap.Entry successor(Entry t) {

  2.         //如果为null,则返回

  3.         if (t == null)

  4.             return null;

  5.         //如果大儿子存在,那么沿着这条路下去,找到其这个枝条中最小的节点

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

  7.             Entry p = t.right;

  8.             while (p.left != null)

  9.                 p = p.left;

  10.             return p;

  11.         } else {

  12.         //如果右边子树是空的,那么找到其长辈节点中间第一个大于他的

  13.             Entry p = t.parent;

  14.             Entry ch = t;

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

  16.                 ch = p;

  17.                 p = p.parent;

  18.             }

  19.             return p;

  20.         }

  21.     }

我们再来看一下我们在获取其集合的时候的顺序:

  1.    static final class KeySet extends AbstractSet implements NavigableSet {

  2.         private final NavigableMap m;

  3.         KeySet(NavigableMap map) { m = map; }


  4.         public Iterator iterator() {

  5.             if (m instanceof TreeMap)

  6.                 return ((TreeMap)m).keyIterator();

  7.             else

  8.                 return (Iterator)(((TreeMap.NavigableSubMap)m).keyIterator());

  9.         }


  10.         public Iterator descendingIterator() {

  11.             if (m instanceof TreeMap)

  12.                 return ((TreeMap)m).descendingKeyIterator();

  13.             else

  14.                 return (Iterator)(((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 comparator() { return m.comparator(); }

  27.         public E pollFirst() {

  28.             Map.Entry e = m.pollFirstEntry();

  29.             return e == null? null : e.getKey();

  30.         }

  31.         public E pollLast() {

  32.             Map.Entry e = m.pollLastEntry();

  33.             return e == null? null : 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 subSet(E fromElement, boolean fromInclusive,

  41.                                       E toElement,   boolean toInclusive) {

  42.             return new TreeSet(m.subMap(fromElement, fromInclusive,

  43.                                            toElement,   toInclusive));

  44.         }

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

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

  47.         }

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

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

  50.         }

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

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

  53.         }

  54.         public SortedSet headSet(E toElement) {

  55.             return headSet(toElement, false);

  56.         }

  57.         public SortedSet tailSet(E fromElement) {

  58.             return tailSet(fromElement, true);

  59.         }

  60.         public NavigableSet descendingSet() {

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

  62.         }

  63.     }

这个是返回的set,他的查找排序是利用的迭代模式委托给了迭代器,我们看看他的迭代器实现:

  1.  final class KeyIterator extends PrivateEntryIterator {

  2.         KeyIterator(Entry first) {

  3.             super(first);

  4.         }

  5.         public K next() {

  6.             return nextEntry().key;

  7.         }

  8.     }

其中获取下一个nextEntry是:

  1. final Entry nextEntry() {

  2.             Entry 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(),在开始的分析中我们知道,successor的查找,是通过了树的中序遍历的

感谢各位的阅读,以上就是“JDK的TreeMap怎么实现”的内容了,经过本文的学习后,相信大家对JDK的TreeMap怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是创新互联网站建设公司,,小编将为大家推送更多相关知识点的文章,欢迎关注!


文章标题:JDK的TreeMap怎么实现-创新互联
分享链接:http://cdweb.net/article/ddhogc.html