1、TreeSet-底层数据结构

  1. 1TreeSet-底层数据结构:
  2. 1-1TreeSet这个类实现了Set集合,实际为一个TreeMap的实例。
  3. 1-2TreeSet,它是基于TreeMap实现的,TreeSet底层使用TreeMap来保存所有元素,因此TreeSet的实现比较简单,相关TreeSet的操作,基本上都是直接调用底层TreeMap的相关方法来完成。
  4. 1-3TreeSet属性字段有:
  5. /**
  6. * The backing map.
  7. * NavigableMap对象
  8. */
  9. private transient NavigableMap<E,Object> m;
  10. //定义一个虚拟的Object对象作为TreeMap的value,将此对象定义为static final。
  11. //PRESENT是键-值对中的值
  12. private static final Object PRESENT = new Object();

2、TreeSet-构造函数

  1. 1TreeSet底层是通过HashSet实现的。
  2. 2、构造方法-源代码:
  3. /**
  4. * 将TreeMap赋值给 "NavigableMap对象m"
  5. */
  6. TreeSet(NavigableMap<E,Object> m) {
  7. this.m = m;
  8. }
  9. // 不带参数的构造函数。创建一个空的TreeMap
  10. public TreeSet() {
  11. this(new TreeMap<E,Object>());
  12. }
  13. // 带比较器的构造函数。
  14. public TreeSet(Comparator<? super E> comparator) {
  15. this(new TreeMap<>(comparator));
  16. }
  17. // 创建TreeSet,并将集合c中的全部元素都添加到TreeSet中
  18. public TreeSet(Collection<? extends E> c) {
  19. this();
  20. addAll(c);
  21. }
  22. // 创建TreeSet,并将s中的全部元素都添加到TreeSet中
  23. public TreeSet(SortedSet<E> s) {
  24. this(s.comparator());
  25. addAll(s);
  26. }

3、TreeSet-添加元素

  1. 1、添加元素:.put()方法
  2. 2、源代码:
  3. public V put(K key, V value) {
  4. //定义一个t来保存根元素
  5. Entry<K,V> t = root;
  6. //如果t==null,表明是一个空链表
  7. if (t == null) {
  8. //如果根节点为null,将传入的键值对构造成根节点(根节点没有父节点,所以传入的父节点为null)
  9. root = new Entry<K,V>(key, value, null);
  10. //设置该集合的size为1
  11. size = 1;
  12. //修改此时+1
  13. modCount++;
  14. return null;
  15. }
  16. // 记录比较结果
  17. int cmp;
  18. Entry<K,V> parent;
  19. // 分割比较器和可比较接口的处理
  20. Comparator<? super K> cpr = comparator;
  21. // 有比较器的处理,即采用定制排序
  22. if (cpr != null) {
  23. // do while实现在root为根节点移动寻找传入键值对需要插入的位置
  24. /**
  25. 实现"排序二叉树"的关键算法。
  26. 1.每当程序希望添加新节点时,总是从树的根节点开始比较,即将根节点当成当前节点。
  27. 1.1.如果新增节点大于当前节点且当前节点的右子节点存在,则以右子节点作为当前节点。并继续循环
  28. 1.2.如果新增节点小于当前节点且当前节点的左子节点存在,则以左子节点作为当前节点。并继续循环
  29. 1.3.如果新增节点等于当前节点,则新增节点覆盖当前节点,并结束循环。
  30. */
  31. do {
  32. //使用parent上次循环后的t所引用的Entry
  33. // 记录将要被掺入新的键值对将要节点(即新节点的父节点)
  34. parent = t;
  35. // 使用比较器比较父节点和插入键值对的key值的大小
  36. cmp = cpr.compare(key, t.key);
  37. // 插入的key较大
  38. if (cmp < 0)
  39. t = t.left;
  40. // 插入的key较小
  41. else if (cmp > 0)
  42. t = t.right;
  43. // key值相等,替换并返回t节点的value(put方法结束)
  44. else
  45. return t.setValue(value);
  46. } while (t != null);
  47. }
  48. // 没有比较器的处理
  49. else {
  50. // key为null抛出NullPointerException异常
  51. if (key == null)
  52. throw new NullPointerException();
  53. Comparable<? super K> k = (Comparable<? super K>) key;
  54. // 与if中的do while类似,只是比较的方式不同
  55. do {
  56. parent = t;
  57. cmp = k.compareTo(t.key);
  58. if (cmp < 0)
  59. t = t.left;
  60. else if (cmp > 0)
  61. t = t.right;
  62. else
  63. return t.setValue(value);
  64. } while (t != null);
  65. }
  66. // 没有找到key相同的节点才会有下面的操作
  67. // 根据传入的键值对和找到的“父节点”创建新节点
  68. Entry<K,V> e = new Entry<K,V>(key, value, parent);
  69. // 根据最后一次的判断结果确认新节点是“父节点”的左孩子还是又孩子
  70. if (cmp < 0)
  71. parent.left = e;
  72. else
  73. parent.right = e;
  74. // 对加入新节点的树进行调整
  75. fixAfterInsertion(e);
  76. // 记录size和modCount
  77. size++;
  78. modCount++;
  79. // 因为是插入新节点,所以返回的是null
  80. return null;
  81. }

4、TreeSet-获取元素

  1. 1、获取元素:.get()方法
  2. 2、源代码:
  3. public V get(Object key) {
  4. //根据key取出Entry
  5. Entry<K,V> p = getEntry(key);
  6. //取出Entry所包含的value
  7. return (p==null ? null : p.value);
  8. }
  9. /**
  10. 利用排序二叉树的特性来搜索目标Entry: 从二叉数的根节点开始,如果被搜索节点大于当前节点,程序向"右子树"搜索,如果小于,则向"左子树"搜索。如果相等则说明找到了指定节点。
  11. */
  12. final Entry<K,V> getEntry(Object key) {
  13. // 如果有比较器,返回getEntryUsingComparator(Object key)的结果
  14. if (comparator != null)
  15. return getEntryUsingComparator(key);
  16. // 查找的key为null,抛出NullPointerException
  17. if (key == null)
  18. throw new NullPointerException();
  19. // 如果没有比较器,而是实现了可比较接口
  20. //将key强制转换为Comparable接口
  21. Comparable<? super K> k = (Comparable<? super K>) key;
  22. // 获取根节点
  23. Entry<K,V> p = root;
  24. // 从根节点开始对树进行遍历查找节点
  25. while (p != null) {
  26. // 把key和当前节点的key进行比较
  27. int cmp = k.compareTo(p.key);
  28. // key小于当前节点的key
  29. if (cmp < 0)
  30. // p “移动”到左节点上
  31. p = p.left;
  32. // key大于当前节点的key
  33. else if (cmp > 0)
  34. // p “移动”到右节点上
  35. p = p.right;
  36. // key值相等则当前节点就是要找的节点
  37. else
  38. // 返回找到的节点
  39. return p;
  40. }
  41. // 没找到则返回null
  42. return null;
  43. }
  44. //在采用定制排序的方式下,TreeMap采用getEntryUsingComparator(key)方法来根据key获取Entry。
  45. final Entry<K,V> getEntryUsingComparator(Object key) {
  46. K k = (K) key;
  47. // 获取比较器
  48. Comparator<? super K> cpr = comparator;
  49. // 其实在调用此方法的get(Object key)中已经对比较器为null的情况进行判断,这里是防御性的判断
  50. if (cpr != null) {
  51. // 获取根节点
  52. Entry<K,V> p = root;
  53. // 遍历树
  54. while (p != null) {
  55. // 获取key和当前节点的key的比较结果
  56. int cmp = cpr.compare(k, p.key);
  57. // 查找的key值较小
  58. if (cmp < 0)
  59. // p“移动”到左孩子
  60. p = p.left;
  61. // 查找的key值较大
  62. else if (cmp > 0)
  63. // p“移动”到右节点
  64. p = p.right;
  65. // key值相等
  66. else
  67. // 返回找到的节点
  68. return p;
  69. }
  70. }
  71. // 没找到key值对应的节点,返回null
  72. return null;
  73. }

5、TreeSet-其他方法-简介

  1. public class TreeSet<E> extends AbstractSet<E>
  2. implements NavigableSet<E>, Cloneable, java.io.Serializable
  3. {
  4. // NavigableMap对象
  5. private transient NavigableMap<E,Object> m;
  6. // TreeSet是通过TreeMap实现的,
  7. // PRESENT是键-值对中的值。
  8. private static final Object PRESENT = new Object();
  9. // 不带参数的构造函数。创建一个空的TreeMap
  10. public TreeSet() {
  11. this(new TreeMap<E,Object>());
  12. }
  13. // 将TreeMap赋值给 "NavigableMap对象m"
  14. TreeSet(NavigableMap<E,Object> m) {
  15. this.m = m;
  16. }
  17. // 带比较器的构造函数。
  18. public TreeSet(Comparator<? super E> comparator) {
  19. this(new TreeMap<E,Object>(comparator));
  20. }
  21. // 创建TreeSet,并将集合c中的全部元素都添加到TreeSet中
  22. public TreeSet(Collection<? extends E> c) {
  23. this();
  24. // 将集合c中的元素全部添加到TreeSet中
  25. addAll(c);
  26. }
  27. // 创建TreeSet,并将s中的全部元素都添加到TreeSet中
  28. public TreeSet(SortedSet<E> s) {
  29. this(s.comparator());
  30. addAll(s);
  31. }
  32. // 返回TreeSet的顺序排列的迭代器。
  33. // 因为TreeSet时TreeMap实现的,所以这里实际上时返回TreeMap的“键集”对应的迭代器
  34. public Iterator<E> iterator() {
  35. return m.navigableKeySet().iterator();
  36. }
  37. // 返回TreeSet的逆序排列的迭代器。
  38. // 因为TreeSet时TreeMap实现的,所以这里实际上时返回TreeMap的“键集”对应的迭代器
  39. public Iterator<E> descendingIterator() {
  40. return m.descendingKeySet().iterator();
  41. }
  42. // 返回TreeSet的大小
  43. public int size() {
  44. return m.size();
  45. }
  46. // 返回TreeSet是否为空
  47. public boolean isEmpty() {
  48. return m.isEmpty();
  49. }
  50. // 返回TreeSet是否包含对象(o)
  51. public boolean contains(Object o) {
  52. return m.containsKey(o);
  53. }
  54. // 添加e到TreeSet中
  55. public boolean add(E e) {
  56. return m.put(e, PRESENT)==null;
  57. }
  58. // 删除TreeSet中的对象o
  59. public boolean remove(Object o) {
  60. return m.remove(o)==PRESENT;
  61. }
  62. // 清空TreeSet
  63. public void clear() {
  64. m.clear();
  65. }
  66. // 将集合c中的全部元素添加到TreeSet中
  67. public boolean addAll(Collection<? extends E> c) {
  68. // Use linear-time version if applicable
  69. if (m.size()==0 && c.size() > 0 &&
  70. c instanceof SortedSet &&
  71. m instanceof TreeMap) {
  72. SortedSet<? extends E> set = (SortedSet<? extends E>) c;
  73. TreeMap<E,Object> map = (TreeMap<E, Object>) m;
  74. Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
  75. Comparator<? super E> mc = map.comparator();
  76. if (cc==mc || (cc != null && cc.equals(mc))) {
  77. map.addAllForTreeSet(set, PRESENT);
  78. return true;
  79. }
  80. }
  81. return super.addAll(c);
  82. }
  83. // 返回子Set,实际上是通过TreeMap的subMap()实现的。
  84. public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
  85. E toElement, boolean toInclusive) {
  86. return new TreeSet<E>(m.subMap(fromElement, fromInclusive,
  87. toElement, toInclusive));
  88. }
  89. // 返回Set的头部,范围是:从头部到toElement。
  90. // inclusive是是否包含toElement的标志
  91. public NavigableSet<E> headSet(E toElement, boolean inclusive) {
  92. return new TreeSet<E>(m.headMap(toElement, inclusive));
  93. }
  94. // 返回Set的尾部,范围是:从fromElement到结尾。
  95. // inclusive是是否包含fromElement的标志
  96. public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
  97. return new TreeSet<E>(m.tailMap(fromElement, inclusive));
  98. }
  99. // 返回子Set。范围是:从fromElement(包括)到toElement(不包括)。
  100. public SortedSet<E> subSet(E fromElement, E toElement) {
  101. return subSet(fromElement, true, toElement, false);
  102. }
  103. // 返回Set的头部,范围是:从头部到toElement(不包括)。
  104. public SortedSet<E> headSet(E toElement) {
  105. return headSet(toElement, false);
  106. }
  107. // 返回Set的尾部,范围是:从fromElement到结尾(不包括)。
  108. public SortedSet<E> tailSet(E fromElement) {
  109. return tailSet(fromElement, true);
  110. }
  111. // 返回Set的比较器
  112. public Comparator<? super E> comparator() {
  113. return m.comparator();
  114. }
  115. // 返回Set的第一个元素
  116. public E first() {
  117. return m.firstKey();
  118. }
  119. // 返回Set的最后一个元素
  120. public E first() {
  121. public E last() {
  122. return m.lastKey();
  123. }
  124. // 返回Set中小于e的最大元素
  125. public E lower(E e) {
  126. return m.lowerKey(e);
  127. }
  128. // 返回Set中小于/等于e的最大元素
  129. public E floor(E e) {
  130. return m.floorKey(e);
  131. }
  132. // 返回Set中大于/等于e的最小元素
  133. public E ceiling(E e) {
  134. return m.ceilingKey(e);
  135. }
  136. // 返回Set中大于e的最小元素
  137. public E higher(E e) {
  138. return m.higherKey(e);
  139. }
  140. // 获取第一个元素,并将该元素从TreeMap中删除。
  141. public E pollFirst() {
  142. Map.Entry<E,?> e = m.pollFirstEntry();
  143. return (e == null)? null : e.getKey();
  144. }
  145. // 获取最后一个元素,并将该元素从TreeMap中删除。
  146. public E pollLast() {
  147. Map.Entry<E,?> e = m.pollLastEntry();
  148. return (e == null)? null : e.getKey();
  149. }
  150. // 克隆一个TreeSet,并返回Object对象
  151. public Object clone() {
  152. TreeSet<E> clone = null;
  153. try {
  154. clone = (TreeSet<E>) super.clone();
  155. } catch (CloneNotSupportedException e) {
  156. throw new InternalError();
  157. }
  158. clone.m = new TreeMap<E,Object>(m);
  159. return clone;
  160. }
  161. // java.io.Serializable的写入函数
  162. // 将TreeSet的“比较器、容量,所有的元素值”都写入到输出流中
  163. private void writeObject(java.io.ObjectOutputStream s)
  164. throws java.io.IOException {
  165. s.defaultWriteObject();
  166. // 写入比较器
  167. s.writeObject(m.comparator());
  168. // 写入容量
  169. s.writeInt(m.size());
  170. // 写入“TreeSet中的每一个元素”
  171. for (Iterator i=m.keySet().iterator(); i.hasNext(); )
  172. s.writeObject(i.next());
  173. }
  174. // java.io.Serializable的读取函数:根据写入方式读出
  175. // 先将TreeSet的“比较器、容量、所有的元素值”依次读出
  176. private void readObject(java.io.ObjectInputStream s)
  177. throws java.io.IOException, ClassNotFoundException {
  178. // Read in any hidden stuff
  179. s.defaultReadObject();
  180. // 从输入流中读取TreeSet的“比较器”
  181. Comparator<? super E> c = (Comparator<? super E>) s.readObject();
  182. TreeMap<E,Object> tm;
  183. if (c==null)
  184. tm = new TreeMap<E,Object>();
  185. else
  186. tm = new TreeMap<E,Object>(c);
  187. m = tm;
  188. // 从输入流中读取TreeSet的“容量”
  189. int size = s.readInt();
  190. // 从输入流中读取TreeSet的“全部元素”
  191. tm.readTreeSet(size, s, PRESENT);
  192. }
  193. // TreeSet的序列版本号
  194. private static final long serialVersionUID = -2479143000061671589L;
  195. }