JDK原始碼分析-TreeSet

小草丶發表於2024-04-29

概述

TreeSet是Java集合框架中用於儲存唯一元素的樹形資料結構,它實現了NavigableSet介面,這意味著TreeSet中的元素不僅是有序的,還支援一系列的導航方法。

TreeSet的內部實現主要依賴於TreeMap,透過TreeMap的鍵來維護元素的排序。

類圖

JDK原始碼分析-TreeSet

從以上類圖可以看到,TreeSet 實現了三個介面,繼承了一個抽象類:

  • NavigableSet介面,提供了強大、靈活的排序與導航功能
  • Serializable介面,表示TreeSet支援序列化功能
  • Cloneable介面,表示TreeSet支援克隆
  • AbstractSet抽象類,主要提供元素對比、刪除等操作

原始碼解讀

成員變數

// 底層依賴TreeMap(TreeMap實現了NavigableMap介面)
private transient NavigableMap<E,Object> m;

// 同HashSet,value使用統一佔位符物件
// value沒有用到為啥不直接用null,因為底層TreeMap插入、移除元素會返回當前元素。如果這裡使用null值,就無法判斷是否插入、移除成功
private static final Object PRESENT = new Object();

構造方法

TreeSet 中提供了四種構造方案:

  • public TreeSet()預設建構函式
  • public TreeSet(Comparator<? super E> comparator)建立一個自定義比較器的TreeSet集合
  • public TreeSet(Collection<? extends E> c)建立一個包含集合c中所有元素的TreeSet集合
  • public TreeSet(SortedSet<E> s)建立一個包含SortedSet集合s中所有元素的TreeSet集合,且會複用s的比較器

新增元素

TreeSet的新增元素操作是透過呼叫TreeMap的put方法實現的。

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

與HashSet類似,如果元素不存在於TreeMap中,put方法會返回null,表示新增成功;如果元素已存在,則返回舊值(在這種情況下是PRESENT),表示新增失敗。

刪除元素

TreeSet的刪除元素操作是透過呼叫TreeMap的remove方法實現的。

public boolean remove(Object o) {
    return m.remove(o)==PRESENT;
}

如果成功刪除了元素,remove方法會返回PRESENT;否則返回null。

獲取元素

TreeSet的獲取元素操作是透過呼叫TreeMap方法實現的,獲取TreeMap key即TreeSet的元素。

// 返回第一個元素
public E first() {
    return m.firstKey();
}
// 返回最後一個元素
public E last() {
    return m.lastKey();
}
// 返回set中小於e的最大的元素
public E lower(E e) {
    return m.lowerKey(e);
}
// 返回set中小於/等於e的最大元素
public E floor(E e) {
    return m.floorKey(e);
}
// 返回set中大於/等於e的最大元素
public E ceiling(E e) {
    return m.ceilingKey(e);
}
// 返回set中大於e的最小元素
public E higher(E e) {
    return m.higherKey(e);
}

遍歷元素

TreeSet的遍歷元素操作是透過呼叫TreeMap方法實現的。升序遍歷(iterator方法)、降序遍歷(descendingIterator方法)。

// 升序遍歷
public Iterator<E> iterator() {
    return m.navigableKeySet().iterator();
}
// 降序遍歷
public Iterator<E> descendingIterator() {
    return m.descendingKeySet().iterator();
}

出棧元素

TreeSet的出棧元素操作是透過呼叫TreeMap方法實現的。頭結點出棧(pollFirst方法)、尾結點出棧(pollLast方法)。

// 獲取TreeSet中第一個元素,並從Set中刪除該元素
public E pollFirst() {
    Map.Entry<E,?> e = m.pollFirstEntry();
    return (e == null) ? null : e.getKey();
}
// 獲取TreeSet中最後一個元素,並從Set中刪除該元素
public E pollLast() {
    Map.Entry<E,?> e = m.pollLastEntry();
    return (e == null) ? null : e.getKey();
}

總結

透過以上的原始碼分析,可以看到TreeSet的底層實現主要依賴於TreeMap。TreeSet利用TreeMap的鍵來儲存元素,並透過TreeMap的排序特性保證了元素的自然排序或自定義排序。

相關文章