1、TreeSet-底层数据结构
1、TreeSet-底层数据结构: 1-1、TreeSet这个类实现了Set集合,实际为一个TreeMap的实例。 1-2、TreeSet,它是基于TreeMap实现的,TreeSet底层使用TreeMap来保存所有元素,因此TreeSet的实现比较简单,相关TreeSet的操作,基本上都是直接调用底层TreeMap的相关方法来完成。 1-3、TreeSet属性字段有: /** * The backing map. * NavigableMap对象 */ private transient NavigableMap<E,Object> m; //定义一个虚拟的Object对象作为TreeMap的value,将此对象定义为static final。 //PRESENT是键-值对中的值 private static final Object PRESENT = new Object();
2、TreeSet-构造函数
1、TreeSet底层是通过HashSet实现的。2、构造方法-源代码: /** * 将TreeMap赋值给 "NavigableMap对象m" */ TreeSet(NavigableMap<E,Object> m) { this.m = m; } // 不带参数的构造函数。创建一个空的TreeMap public TreeSet() { this(new TreeMap<E,Object>()); } // 带比较器的构造函数。 public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<>(comparator)); } // 创建TreeSet,并将集合c中的全部元素都添加到TreeSet中 public TreeSet(Collection<? extends E> c) { this(); addAll(c); } // 创建TreeSet,并将s中的全部元素都添加到TreeSet中 public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); }
3、TreeSet-添加元素
1、添加元素:.put()方法2、源代码: public V put(K key, V value) { //定义一个t来保存根元素 Entry<K,V> t = root; //如果t==null,表明是一个空链表 if (t == null) { //如果根节点为null,将传入的键值对构造成根节点(根节点没有父节点,所以传入的父节点为null) root = new Entry<K,V>(key, value, null); //设置该集合的size为1 size = 1; //修改此时+1 modCount++; return null; } // 记录比较结果 int cmp; Entry<K,V> parent; // 分割比较器和可比较接口的处理 Comparator<? super K> cpr = comparator; // 有比较器的处理,即采用定制排序 if (cpr != null) { // do while实现在root为根节点移动寻找传入键值对需要插入的位置 /** 实现"排序二叉树"的关键算法。 1.每当程序希望添加新节点时,总是从树的根节点开始比较,即将根节点当成当前节点。 1.1.如果新增节点大于当前节点且当前节点的右子节点存在,则以右子节点作为当前节点。并继续循环 1.2.如果新增节点小于当前节点且当前节点的左子节点存在,则以左子节点作为当前节点。并继续循环 1.3.如果新增节点等于当前节点,则新增节点覆盖当前节点,并结束循环。 */ do { //使用parent上次循环后的t所引用的Entry // 记录将要被掺入新的键值对将要节点(即新节点的父节点) parent = t; // 使用比较器比较父节点和插入键值对的key值的大小 cmp = cpr.compare(key, t.key); // 插入的key较大 if (cmp < 0) t = t.left; // 插入的key较小 else if (cmp > 0) t = t.right; // key值相等,替换并返回t节点的value(put方法结束) else return t.setValue(value); } while (t != null); } // 没有比较器的处理 else { // key为null抛出NullPointerException异常 if (key == null) throw new NullPointerException(); Comparable<? super K> k = (Comparable<? super K>) key; // 与if中的do while类似,只是比较的方式不同 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); } // 没有找到key相同的节点才会有下面的操作 // 根据传入的键值对和找到的“父节点”创建新节点 Entry<K,V> e = new Entry<K,V>(key, value, parent); // 根据最后一次的判断结果确认新节点是“父节点”的左孩子还是又孩子 if (cmp < 0) parent.left = e; else parent.right = e; // 对加入新节点的树进行调整 fixAfterInsertion(e); // 记录size和modCount size++; modCount++; // 因为是插入新节点,所以返回的是null return null; }
4、TreeSet-获取元素
1、获取元素:.get()方法2、源代码: public V get(Object key) { //根据key取出Entry Entry<K,V> p = getEntry(key); //取出Entry所包含的value return (p==null ? null : p.value); } /** 利用排序二叉树的特性来搜索目标Entry: 从二叉数的根节点开始,如果被搜索节点大于当前节点,程序向"右子树"搜索,如果小于,则向"左子树"搜索。如果相等则说明找到了指定节点。 */ final Entry<K,V> getEntry(Object key) { // 如果有比较器,返回getEntryUsingComparator(Object key)的结果 if (comparator != null) return getEntryUsingComparator(key); // 查找的key为null,抛出NullPointerException if (key == null) throw new NullPointerException(); // 如果没有比较器,而是实现了可比较接口 //将key强制转换为Comparable接口 Comparable<? super K> k = (Comparable<? super K>) key; // 获取根节点 Entry<K,V> p = root; // 从根节点开始对树进行遍历查找节点 while (p != null) { // 把key和当前节点的key进行比较 int cmp = k.compareTo(p.key); // key小于当前节点的key if (cmp < 0) // p “移动”到左节点上 p = p.left; // key大于当前节点的key else if (cmp > 0) // p “移动”到右节点上 p = p.right; // key值相等则当前节点就是要找的节点 else // 返回找到的节点 return p; } // 没找到则返回null return null; } //在采用定制排序的方式下,TreeMap采用getEntryUsingComparator(key)方法来根据key获取Entry。 final Entry<K,V> getEntryUsingComparator(Object key) { K k = (K) key; // 获取比较器 Comparator<? super K> cpr = comparator; // 其实在调用此方法的get(Object key)中已经对比较器为null的情况进行判断,这里是防御性的判断 if (cpr != null) { // 获取根节点 Entry<K,V> p = root; // 遍历树 while (p != null) { // 获取key和当前节点的key的比较结果 int cmp = cpr.compare(k, p.key); // 查找的key值较小 if (cmp < 0) // p“移动”到左孩子 p = p.left; // 查找的key值较大 else if (cmp > 0) // p“移动”到右节点 p = p.right; // key值相等 else // 返回找到的节点 return p; } } // 没找到key值对应的节点,返回null return null; }
5、TreeSet-其他方法-简介
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, java.io.Serializable{ // NavigableMap对象 private transient NavigableMap<E,Object> m; // TreeSet是通过TreeMap实现的, // PRESENT是键-值对中的值。 private static final Object PRESENT = new Object(); // 不带参数的构造函数。创建一个空的TreeMap public TreeSet() { this(new TreeMap<E,Object>()); } // 将TreeMap赋值给 "NavigableMap对象m" TreeSet(NavigableMap<E,Object> m) { this.m = m; } // 带比较器的构造函数。 public TreeSet(Comparator<? super E> comparator) { this(new TreeMap<E,Object>(comparator)); } // 创建TreeSet,并将集合c中的全部元素都添加到TreeSet中 public TreeSet(Collection<? extends E> c) { this(); // 将集合c中的元素全部添加到TreeSet中 addAll(c); } // 创建TreeSet,并将s中的全部元素都添加到TreeSet中 public TreeSet(SortedSet<E> s) { this(s.comparator()); addAll(s); } // 返回TreeSet的顺序排列的迭代器。 // 因为TreeSet时TreeMap实现的,所以这里实际上时返回TreeMap的“键集”对应的迭代器 public Iterator<E> iterator() { return m.navigableKeySet().iterator(); } // 返回TreeSet的逆序排列的迭代器。 // 因为TreeSet时TreeMap实现的,所以这里实际上时返回TreeMap的“键集”对应的迭代器 public Iterator<E> descendingIterator() { return m.descendingKeySet().iterator(); } // 返回TreeSet的大小 public int size() { return m.size(); } // 返回TreeSet是否为空 public boolean isEmpty() { return m.isEmpty(); } // 返回TreeSet是否包含对象(o) public boolean contains(Object o) { return m.containsKey(o); } // 添加e到TreeSet中 public boolean add(E e) { return m.put(e, PRESENT)==null; } // 删除TreeSet中的对象o public boolean remove(Object o) { return m.remove(o)==PRESENT; } // 清空TreeSet public void clear() { m.clear(); } // 将集合c中的全部元素添加到TreeSet中 public boolean addAll(Collection<? extends E> c) { // Use linear-time version if applicable if (m.size()==0 && c.size() > 0 && c instanceof SortedSet && m instanceof TreeMap) { SortedSet<? extends E> set = (SortedSet<? extends E>) c; TreeMap<E,Object> map = (TreeMap<E, Object>) m; Comparator<? super E> cc = (Comparator<? super E>) set.comparator(); Comparator<? super E> mc = map.comparator(); if (cc==mc || (cc != null && cc.equals(mc))) { map.addAllForTreeSet(set, PRESENT); return true; } } return super.addAll(c); } // 返回子Set,实际上是通过TreeMap的subMap()实现的。 public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { return new TreeSet<E>(m.subMap(fromElement, fromInclusive, toElement, toInclusive)); } // 返回Set的头部,范围是:从头部到toElement。 // inclusive是是否包含toElement的标志 public NavigableSet<E> headSet(E toElement, boolean inclusive) { return new TreeSet<E>(m.headMap(toElement, inclusive)); } // 返回Set的尾部,范围是:从fromElement到结尾。 // inclusive是是否包含fromElement的标志 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { return new TreeSet<E>(m.tailMap(fromElement, inclusive)); } // 返回子Set。范围是:从fromElement(包括)到toElement(不包括)。 public SortedSet<E> subSet(E fromElement, E toElement) { return subSet(fromElement, true, toElement, false); } // 返回Set的头部,范围是:从头部到toElement(不包括)。 public SortedSet<E> headSet(E toElement) { return headSet(toElement, false); } // 返回Set的尾部,范围是:从fromElement到结尾(不包括)。 public SortedSet<E> tailSet(E fromElement) { return tailSet(fromElement, true); } // 返回Set的比较器 public Comparator<? super E> comparator() { return m.comparator(); } // 返回Set的第一个元素 public E first() { return m.firstKey(); } // 返回Set的最后一个元素 public E first() { 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); } // 获取第一个元素,并将该元素从TreeMap中删除。 public E pollFirst() { Map.Entry<E,?> e = m.pollFirstEntry(); return (e == null)? null : e.getKey(); } // 获取最后一个元素,并将该元素从TreeMap中删除。 public E pollLast() { Map.Entry<E,?> e = m.pollLastEntry(); return (e == null)? null : e.getKey(); } // 克隆一个TreeSet,并返回Object对象 public Object clone() { TreeSet<E> clone = null; try { clone = (TreeSet<E>) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } clone.m = new TreeMap<E,Object>(m); return clone; } // java.io.Serializable的写入函数 // 将TreeSet的“比较器、容量,所有的元素值”都写入到输出流中 private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); // 写入比较器 s.writeObject(m.comparator()); // 写入容量 s.writeInt(m.size()); // 写入“TreeSet中的每一个元素” for (Iterator i=m.keySet().iterator(); i.hasNext(); ) s.writeObject(i.next()); } // java.io.Serializable的读取函数:根据写入方式读出 // 先将TreeSet的“比较器、容量、所有的元素值”依次读出 private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden stuff s.defaultReadObject(); // 从输入流中读取TreeSet的“比较器” Comparator<? super E> c = (Comparator<? super E>) s.readObject(); TreeMap<E,Object> tm; if (c==null) tm = new TreeMap<E,Object>(); else tm = new TreeMap<E,Object>(c); m = tm; // 从输入流中读取TreeSet的“容量” int size = s.readInt(); // 从输入流中读取TreeSet的“全部元素” tm.readTreeSet(size, s, PRESENT); } // TreeSet的序列版本号 private static final long serialVersionUID = -2479143000061671589L;}