IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

JDK1.8源码(十一)——java.util.TreeMap类

IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

  在前面几篇博客分别介绍了这样几种集合,基于数组实现的ArrayList 类,基于链表实现的LinkedList 类,基于散列表实现的HashMap 类,本篇博客我们来介绍另一种数据类型,基于树实现的TreeSet类。

1、TreeMap 定义

  听名字就知道,TreeMap 是由Tree 和 Map 集合有关的,没错,TreeMap 是由红黑树实现的有序的 key-value 集合。

  PS:想要学懂TreeMap的实现原理,红黑树的了解是必不可少的!!!

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable

  116_1.png

  TreeMap 首先继承了 AbstractMap 抽象类,表示它具有散列表的性质,也就是由 key-value 组成。

  其次 TreeMap 实现了 NavigableMap 接口,该接口支持一系列获取指定集合的导航方法,比如获取小于指定key的集合。

  最后分别实现 Serializable 接口以及 Cloneable 接口,分别表示支持对象序列化以及对象克隆

2、字段定义

  ①、Comparator

    /**
     * The comparator used to maintain order in this tree map, or
     * null if it uses the natural ordering of its keys.
     *
     * @serial
     */
    private final Comparator<? super K> comparator;

  可以看上面的英文注释,Comparator 是用来维护treemap集合中的顺序,如果为null,则按照key的自然顺序。

  Comparator 是一个接口,排序时需要实现其 compare 方法,该方法返回正数,零,负数分别代表大于,等于,小于。那么怎么使用呢?这里举个例子:

  这里有一个Person类,里面有两个属性pname,page,我们将该person对象放入ArrayList集合时,需要对其按照年龄进行排序。

116_2.png 116_3.png

 package com.ys.test;

 /**
  * Create by YSOcean
  */
 public class Person {
     private String pname;
     private Integer page;

     public Person() {
     }

     public Person(String pname, Integer page) {
         this.pname = pname;
         this.page = page;
     }

     public String getPname() {
         return pname;
     }

     public void setPname(String pname) {
         this.pname = pname;
     }

     public Integer getPage() {
         return page;
     }

     public void setPage(Integer page) {
         this.page = page;
     }

     @Override
     public String toString() {
         return "Person{" +
                 "pname='" + pname + '\'' +
                 ", page=" + page +
                 '}';
     }
 }

View Code

  排序代码:

 List<Person> personList = new ArrayList<>();
 personList.add(new Person("李四",20));
 personList.add(new Person("张三",10));
 personList.add(new Person("王五",30));
 System.out.println("原始顺序为:"+personList.toString());
 Collections.sort(personList, new Comparator<Person>() {
     @Override
     public int compare(Person o1, Person o2) {
         //升序
         //return o1.getPage()-o2.getPage();
         //降序
         return o2.getPage()-o1.getPage();
         //不变
         //return 0
     }
 });
 System.out.println("排序后顺序为:"+personList.toString());

  打印结果为:

  116_4.png

  ②、Entry

private transient Entry<K,V> root;

  对于Entry详细源码如下:

116_5.png 116_6.png

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

         /**
          * Returns the key.
          *
          * @return the key
          */
         public K getKey() {
             return key;
         }

         /**
          * Returns the value associated with the key.
          *
          * @return the value associated with the key
          */
         public V getValue() {
             return value;
         }

         /**
          * Replaces the value currently associated with the key with the given
          * value.
          *
          * @return the value associated with the key before this method was
          *         called
          */
         public V setValue(V value) {
             V oldValue = this.value;
             this.value = value;
             return oldValue;
         }

         public boolean equals(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
             Map.Entry<?,?> e = (Map.Entry<?,?>)o;

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

         public int hashCode() {
             int keyHash = (key==null ? 0 : key.hashCode());
             int valueHash = (value==null ? 0 : value.hashCode());
             return keyHash ^ valueHash;
         }

         public String toString() {
             return key + "=" + value;
         }
     }

View Code

  这里主要看 Entry 类的几个字段:

K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;

  相信对红黑树这种数据结构了解的人,一看这几个字段就明白了,这也印证了前面所说的TreeMap底层有红黑树这种数据结构。

  ③、size

    /**
     * The number of entries in the tree
     */
    private transient int size = 0;

  用来表示entry的个数,也就是key-value的个数。

  ④、modCount

    /**
     * The number of structural modifications to the tree.
     */
    private transient int modCount = 0;

  基本上前面讲的在ArrayList,LinkedList,HashMap等线程不安全的集合都有此字段,用来实现Fail-Fast 机制,如果在迭代这些集合的过程中,有其他线程修改了这些集合,就会抛出ConcurrentModificationException异常。

  ⑤、红黑树常量

    private static final boolean RED   = false;
    private static final boolean BLACK = true;

3、构造函数

  ①、无参构造函数

     public TreeMap() {
         comparator = null;
     }

  将比较器 comparator 置为 null,表示按照key的自然顺序进行排序。

  ②、带比较器的构造函数

     public TreeMap(Comparator<? super K> comparator) {
         this.comparator = comparator;
     }

  需要自己实现Comparator。

  ③、构造包含指定map集合的元素

     public TreeMap(Map<? extends K, ? extends V> m) {
         comparator = null;
         putAll(m);
     }

  使用该构造器创建的TreeMap,会默认插入m表示的集合元素,并且comparator表示按照自然顺序进行插入。

  ④、带 SortedMap的构造函数

     public TreeMap(SortedMap<K, ? extends V> m) {
         comparator = m.comparator();
         try {
             buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
         } catch (java.io.IOException cannotHappen) {
         } catch (ClassNotFoundException cannotHappen) {
         }
     }

  和上面带Map的构造函数不一样,map是无序的,而SortedMap 是有序的,使用 buildFromSorted() 方法将SortedMap集合中的元素插入到TreeMap 中。

4、添加元素

     //添加元素
     public V put(K key, V value) {
         TreeMap.Entry<K,V> t = root;
         //如果根节点为空,即TreeMap中一个元素都没有,那么设置新添加的元素为根节点
         //并且设置集合大小size=1,以及modCount+1,这是用于快速失败
         if (t == null) {
             compare(key, key); // type (and possibly null) check

             root = new TreeMap.Entry<>(key, value, null);
             size = 1;
             modCount++;
             return null;
         }
         int cmp;
         TreeMap.Entry<K,V> parent;
         // split comparator and comparable paths
         Comparator<? super K> cpr = comparator;
         //如果比较器不为空,即初始化TreeMap构造函数时,有传递comparator类
         //那么插入新的元素时,按照comparator实现的类进行排序
         if (cpr != null) {
             //通过do-while循环不断遍历树,调用比较器对key值进行比较
             do {
                 parent = t;
                 cmp = cpr.compare(key, t.key);
                 if (cmp < 0)
                     t = t.left;
                 else if (cmp > 0)
                     t = t.right;
                 else
                     //遇到key相等,直接将新值覆盖到原值上
                     return t.setValue(value);
             } while (t != null);
         }
         //如果比较器为空,即初始化TreeMap构造函数时,没有传递comparator类
         //那么插入新的元素时,按照key的自然顺序
         else {
             //如果key==null,直接抛出异常
             //注意,上面构造TreeMap传入了Comparator,是可以允许key==null
             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);
         }
         //找到父亲节点,根据父亲节点创建一个新节点
         TreeMap.Entry<K,V> e = new TreeMap.Entry<>(key, value, parent);
         if (cmp < 0)
             parent.left = e;
         else
             parent.right = e;
         //修正红黑树(包括节点的左旋和右旋,具体可以看我Java数据结构和算法中对红黑树的介绍)
         fixAfterInsertion(e);
         size++;
         modCount++;
         return null;
     }

  添加元素,如果初始化TreeMap构造函数时,没有传递comparator类,是不允许插入key==null的键值对的,相反,如果实现了Comparator,则可以传递key=null的键值对。

  另外,当插入一个新的元素后(除了根节点),会对TreeMap数据结构进行修正,也就是对红黑树进行修正,使其满足红黑树的几个特点,具体修正方法包括改变节点颜色,左旋,右旋等操作,这里我不做详细介绍了,具体可以参考我的这篇博客:https://www.cnblogs.com/ysocean/p/8004211.html

5、删除元素

  ①、根据key删除

     public V remove(Object key) {
         //根据key找到该节点
         TreeMap.Entry<K,V> p = getEntry(key);
         if (p == null)
             return null;
         //获取该节点的value,并返回
         V oldValue = p.value;
         //调用deleteEntry()方法删除节点
         deleteEntry(p);
         return oldValue;
     }

     private void deleteEntry(TreeMap.Entry<K,V> p) {
         modCount++;
         size--;

         //如果删除节点的左右节点都不为空,即有两个孩子
         if (p.left != null && p.right != null) {
             //得到该节点的中序后继节点
             TreeMap.Entry<K,V> s = successor(p);
             p.key = s.key;
             p.value = s.value;
             p = s;
         } // p has 2 children

         // Start fixup at replacement node, if it exists.
         TreeMap.Entry<K,V> replacement = (p.left != null ? p.left : p.right);
         //待删除节点只有一个子节点,直接删除该节点,并用该节点的唯一子节点顶替该节点
         if (replacement != null) {
             // Link replacement to parent
             replacement.parent = p.parent;
             if (p.parent == null)
                 root = replacement;
             else if (p == p.parent.left)
                 p.parent.left  = replacement;
             else
                 p.parent.right = replacement;

             // Null out links so they are OK to use by fixAfterDeletion.
             p.left = p.right = p.parent = null;

             // Fix replacement
             if (p.color == BLACK)
                 fixAfterDeletion(replacement);

             //TreeMap中只有待删除节点P,也就是只有一个节点,直接返回nul即可
         } else if (p.parent == null) { // return if we are the only node.
             root = null;
         } else { //  No children. Use self as phantom replacement and unlink.
             //待删除节点没有子节点,即为叶子节点,直接删除即可
             if (p.color == BLACK)
                 fixAfterDeletion(p);

             if (p.parent != null) {
                 if (p == p.parent.left)
                     p.parent.left = null;
                 else if (p == p.parent.right)
                     p.parent.right = null;
                 p.parent = null;
             }
         }
     }

  删除节点分为四种情况:

  1、根据key没有找到该节点:也就是集合中不存在这一个节点,直接返回null即可。

  2、根据key找到节点,又分为三种情况:

    ①、待删除节点没有子节点,即为叶子节点:直接删除该节点即可。

    ②、待删除节点只有一个子节点:那么首先找到待删除节点的子节点,然后删除该节点,用其唯一子节点顶替该节点。

    ③、待删除节点有两个子节点:首先找到该节点的中序后继节点,然后把这个后继节点的内容复制给待删除节点,然后删除该中序后继节点,删除过程又转换成前面①、②两种情况了,这里主要是找到中序后继节点,相当于待删除节点的一个替身。

6、查找元素

  ①、根据key查找

     public V get(Object key) {
         TreeMap.Entry<K,V> p = getEntry(key);
         return (p==null ? null : p.value);
     }

     final TreeMap.Entry<K,V> getEntry(Object key) {
         // Offload comparator-based version for sake of performance
         if (comparator != null)
             return getEntryUsingComparator(key);
         if (key == null)
             throw new NullPointerException();
         @SuppressWarnings("unchecked")
         Comparable<? super K> k = (Comparable<? super K>) key;
         TreeMap.Entry<K,V> p = root;
         while (p != null) {
             int cmp = k.compareTo(p.key);
             if (cmp < 0)
                 p = p.left;
             else if (cmp > 0)
                 p = p.right;
             else
                 return p;
         }
         return null;
     }

7、遍历元素

  通常有下面两种方法,第二种方法效率要快很多。

 TreeMap<String,Integer> map = new TreeMap<>();
 map.put("A",1);
 map.put("B",2);
 map.put("C",3);

 //第一种方法
 //首先利用keySet()方法得到key的集合,然后利用map.get()方法根据key得到value
 Iterator<String> iterator = map.keySet().iterator();
 while(iterator.hasNext()){
     String key = iterator.next();
     System.out.println(key+":"+map.get(key));
 }

 //第二种方法
 Iterator<Map.Entry<String,Integer>> iterator1 = map.entrySet().iterator();
 while(iterator1.hasNext()){
     Map.Entry<String,Integer> entry = iterator1.next();
     System.out.println(entry.getKey()+":"+entry.getValue());
 }

来源:https://www.cnblogs.com/ysocean/category/1149707.html

文章永久链接:https://tech.souyunku.com/?p=14792


Warning: A non-numeric value encountered in /data/wangzhan/tech.souyunku.com.wp/wp-content/themes/dux/functions-theme.php on line 1154
赞(64) 打赏



未经允许不得转载:搜云库技术团队 » JDK1.8源码(十一)——java.util.TreeMap类

IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码
IDEA2023.1.3破解,IDEA破解,IDEA 2023.1破解,最新IDEA激活码

评论 抢沙发

大前端WP主题 更专业 更方便

联系我们联系我们

觉得文章有用就打赏一下文章作者

微信扫一扫打赏

微信扫一扫打赏


Fatal error: Uncaught Exception: Cache directory not writable. Comet Cache needs this directory please: `/data/wangzhan/tech.souyunku.com.wp/wp-content/cache/comet-cache/cache/https/tech-souyunku-com/index.q`. Set permissions to `755` or higher; `777` might be needed in some cases. in /data/wangzhan/tech.souyunku.com.wp/wp-content/plugins/comet-cache/src/includes/traits/Ac/ObUtils.php:367 Stack trace: #0 [internal function]: WebSharks\CometCache\Classes\AdvancedCache->outputBufferCallbackHandler() #1 /data/wangzhan/tech.souyunku.com.wp/wp-includes/functions.php(5109): ob_end_flush() #2 /data/wangzhan/tech.souyunku.com.wp/wp-includes/class-wp-hook.php(303): wp_ob_end_flush_all() #3 /data/wangzhan/tech.souyunku.com.wp/wp-includes/class-wp-hook.php(327): WP_Hook->apply_filters() #4 /data/wangzhan/tech.souyunku.com.wp/wp-includes/plugin.php(470): WP_Hook->do_action() #5 /data/wangzhan/tech.souyunku.com.wp/wp-includes/load.php(1097): do_action() #6 [internal function]: shutdown_action_hook() #7 {main} thrown in /data/wangzhan/tech.souyunku.com.wp/wp-content/plugins/comet-cache/src/includes/traits/Ac/ObUtils.php on line 367