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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM