• Java 集合类 TreeSet、TreeMap


    TreeMap和TreeSet的异同:

    相同点:

    1. TreeMap和TreeSet都是有序的集合,也就是说他们存储的值都是拍好序的。
    • TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间共享,不过可以使用方法Collections.synchroinzedMap()来实现同步
    • 运行速度都要比Hash集合慢,他们内部对元素的操作时间复杂度为O(logN),而HashMap/HashSet则为O(1)。

    不同点:

    1. 最主要的区别就是TreeSet和TreeMap非别实现Set和Map接口
    • TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)
    • TreeSet中不能有重复对象,而TreeMap中可以存在

    TreeSet的是NavigableSet的实现类,NavigableSet继承了SortedSet接口,SortedSet是Set的子接口;

     1 public class TreeSet<E> extends AbstractSet<E>
     2     implements NavigableSet<E>, Cloneable, java.io.Serializable
     3 {
     4   /**
     5     * The backing map.
     6     */
     7   private transient NavigableMap<E,Object> m;
     8 
     9     // Dummy value to associate with an Object in the backing Map
    10     private static final Object PRESENT = new Object();
    11 
    12   /**
    13      * Constructs a set backed by the specified navigable map.
    14      */
    15     TreeSet(NavigableMap<E,Object> m) {
    16         this.m = m;
    17     }
    18 
    19     /**
    20      * Constructs a new, empty tree set, sorted according to the
    21      * natural ordering of its elements.  All elements inserted into
    22      * the set must implement the {@link Comparable} interface.
    23      * Furthermore, all such elements must be <i>mutually
    24      * comparable</i>: {@code e1.compareTo(e2)} must not throw a
    25      * {@code ClassCastException} for any elements {@code e1} and
    26      * {@code e2} in the set.  If the user attempts to add an element
    27      * to the set that violates this constraint (for example, the user
    28      * attempts to add a string element to a set whose elements are
    29      * integers), the {@code add} call will throw a
    30      * {@code ClassCastException}.
    31      */
    32     public TreeSet() {
    33         this(new TreeMap<E,Object>());
    34     }
    35   .......
    36 }

    由上面的TreeSet的源码可以看出,TreeSet的底层实现是通过TreeMap实现的,而TreeMap的底层又是如何实现的呢?

     1   public TreeMap() {
     2         comparator = null;
     3   }
     4 
     5  public TreeMap(Comparator<? super K> comparator) {
     6         this.comparator = comparator;
     7    }
     8 .....(其他构造方法不一一列举)
     9 //这里列举put方法详细讲解
    10  public V put(K key, V value) {
    11         Entry<K,V> t = root;
    12         if (t == null) {
    13             compare(key, key); // type (and possibly null) check
    14 
    15             root = new Entry<>(key, value, null);
    16             size = 1;
    17             modCount++;
    18             return null;
    19         }
    20         int cmp;
    21         Entry<K,V> parent;
    22         // split comparator and comparable paths
    23         Comparator<? super K> cpr = comparator;
    24         if (cpr != null) {
    25             do {
    26                 parent = t;
    27                 cmp = cpr.compare(key, t.key);
    28                 if (cmp < 0)
    29                     t = t.left;
    30                 else if (cmp > 0)
    31                     t = t.right;
    32                 else
    33                     return t.setValue(value);
    34             } while (t != null);
    35         }
    36         else {
    37             if (key == null)
    38                 throw new NullPointerException();
    39             Comparable<? super K> k = (Comparable<? super K>) key;
    40             do {
    41                 parent = t;
    42                 cmp = k.compareTo(t.key);
    43                 if (cmp < 0)
    44                     t = t.left;
    45                 else if (cmp > 0)
    46                     t = t.right;
    47                 else
    48                     return t.setValue(value);
    49             } while (t != null);
    50         }
    51         Entry<K,V> e = new Entry<>(key, value, parent);
    52         if (cmp < 0)
    53             parent.left = e;
    54         else
    55             parent.right = e;
    56         fixAfterInsertion(e);
    57         size++;
    58         modCount++;
    59         return null;
    60     }

    从上面的TreeMap的两个构造方法和插入方法可以看出当第一次插入时,返回null,插入值不同时返回null;否则返回值不为null;这里需要注意以下几点:

    1、创 建TreeSet或者TreeMap时候采用有参构造函数并且参数是Comparator时候,参数必须是Comparator的实现子类;而利用无参构 造函数时,向TreeSet或者TreeMap添加元素是需要特别注意所添加的对象必须是实现了Comparable接口的子类否则会报错(对象类型 cannot be cast to java.lang.Comparable),这也是TreeMap的put方法中实现的原因,这是多态的表现,父类对象指向子类引用;

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

    2、由于TreeSet和TreeMap的底层都是树形结构,而且每一个节点的对象是Entry对象

    1         K key;
    2         V value;
    3         Entry<K,V> left = null;
    4         Entry<K,V> right = null;
    5         Entry<K,V> parent;   

    这是Entry的结构,是一个类似链表节点的树形结构;

    3、TreeSet和TreeMap的底层都是树形结构是一个二叉查找树,并且是一个红黑平衡树,实现方法:

     fixAfterInsertion(e);
  • 相关阅读:
    正则表达式在线测试(生成)工具
    org.eclipse.swt.custom.StyledText.getScrollbarsMode()I
    MySQL修改表一次添加多个列(字段)和索引
    How can I view currently running MySQL queries?( 查看正在运行的MySQL语句/脚本命令)
    faster alter table add column
    提取data.frame中的部分数据(不含列标题和行标题)
    How to generate a random number in R
    INSTALLMENT of QValue
    Linux 执行ll命令时指定按文件时间或大小排序
    替换 data.frame 中的特殊的值
  • 原文地址:https://www.cnblogs.com/scyitgz/p/5103690.html
Copyright © 2020-2023  润新知