【0】README
【1】树集(TreeSet)(用到了红黑树)
1.1)树集是一个有序集合。可以以任意顺序将元素插入到集合中, 在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现;
1.1.1)看个荔枝:
SortedSet sorter = new TreeSet<>(); // TreeSet implements SortedSet
sorter.add("bob");
sorter.add("car");
sorter.add("amy");
for(String s: sorter)
System.println(s);
1.1.2)将元素添加到 树(TreeSet)中要比添加到散列表(HashSet)中慢, 但是,与将元素添加到数组或链表的正确位置上相比还是快很多的;
Attention) TreeSet 的排序功能用到了红黑树, 因此迭代器总是以排好序的顺序访问每个元素)
API java.util.TreeSet 1.2
TreeSet():构造一个空树集;
TreeSet(Collection extends E> elements):构造一个树集, 并将集合中所有元素添加到树集中;
【2】对象的比较
2.1) TreeSet如何知道希望元素怎样排列呢? 在默认情况下, 树集假定插入的元素实现了 Comparable 接口, 这个接口定义了一个方法:
public interface Comparable
{
in compareTo(T other);
}
2.1.1)排序后,a在b的前面,后面或相等,分别返回 负值,正值,0;
2.1.2)有些标准的 java 平台类实现了 Comparable接口,如, String类, 这个类的compareTo() 方法依据字典顺序对字符串进行比较;
2.2)如果要插入自定义对象, 就必须通过实现 Comparable接口自定义排列顺序。
Attention)在 Object类中, 没有提供任何 compareTo 接口的默认实现 (干货);
2.2.1)看个荔枝:(展示了如何用部件编号对 Item 对象进行排序)
class Item implements Comparable {
public int compareTo(Item other)
{
return partNumber - other.partNumber;
}
}
Warning)只有整数在一个足够小的范围内,才可以使用这个技巧。 如果x是一个较大的正整数, y是一个较大的负整数, x-y 有可能会溢出;
2.3)出现的问题+解决方法
2.3.1)出现的问题:使用 Comparable接口定义排列排序显然有其局限性。对于一个给定的类, 只能实现这个接口一次。如果在一个集合中需要按照部件编号进行排序, 在另一个集合中 却要按照描述信息进行排序, 该怎么办呢?还有,如果需要对一个类的对象进行排序, 而这个类的创建者又没有实现 Comparable接口, 又该怎么办呢?
2.3.2)解决方法: 通过将 Comparator 对象传递给TreeSet构造器来告诉树集使用不同的比较方法。 Comparator接口声明了一个带有两个显式参数的compare 方法:
public interface Comparator
{
int compare(T a, T b);
}
(即, 当两个不同集合中的元素的排序规则不同, 就要引入Comparator)
2.3.2.1)与 compareTo() 方法一样,a在b之前,之后,或相等, 分别返回 正值, 负值和零;所以,我们直接定义一个 实现 Comparator 接口的类:
class ItemComparator implements Comparator {
public int compare(Item a, Item b)
{
String desrcA = a.getDescription();
String desrcB = b.getDescription();
String desrcA.compareTo(desrcB);
}
}
2.3.2.2)然后将这个类对象传递给树集的构造器:
ItemComparator comp = new ItemComparator();
SortedSort sort = new TreeSet<>(comp);
Attention)
A1) 注意, 这个比较器没有任何数据, 它只是比较方法的持有器。有时将这种对象称为函数对象。
A2)函数对象通常动态定义, 即定义为匿名内部类的实例:
SortedSet set = new TreeSet<>(new
Comparable(){ //匿名 内部类;
public int compare(Item a, Item b) // 匿名内部类中的方法;
{
String desrcA = a.getDescription();
String desrcB = b.getDescription();
String desrcA.compareTo(desrcB);
}
});
Annotation)
A1)实际上, Comparator 接口声明了两个方法:compare 和 equals;
A2)当然,每个类都有一个 equals 方法, 因此, 为这个接口声明再添加一个 equals 方法似乎没有太大的好处;
A3) API文档说, 不需要覆盖equals 方法, 但这样做可能会在某些情况下 提高性能;
2.4)下面的图是否给了我们的疑虑:是否总应该用 树集(TreeSet)取代散列集(HashSet)?
2.4.1)因为添加一个元素所花费的时间看上去并不很长, 而且元素时自动排序的;
2.4.2)到底应该怎样做将取决于 所要收集的数据。如果不需要对数据进行排序,就没有必要付出排序开销 (干货,如何选择集类型, 是树集TreeSet 还是 散列集 HashSet)。
2.4.3)更重要的是, 对其排序要比 散列函数更加困难, 因为散列函数只是将对象适
2.5)收集矩形集(just for coarse understanding):想具体了解树集和散列集间的差异, 还需要研究一个收集矩形集的任务。如果使用 TreeSet, 就需要提供 Comparator;
2.5.1)如何比较两个矩形呢? 比较面积吗。这行不通。可能会有两个不同的矩形, 它们的坐标不同, 但面积却相同。 树的排序必须是全序的。也就是说, 任意两个元素是可比的,并且只有在两个元素相等时才return 0;
2.5.2)确实, 有一种矩形的排序方式, (按照坐标的字典顺序排序), 但它的计算很牵强且很繁琐。 相反地, Rectangle 类已经定义了散列函数, 它直接对坐标进行散列;
Annotation) 从 Java SE 6 开始, TreeSet 类实现了 NavigableSet 接口。 这个接口增加了几个便于定位元素以及反向遍历的方法;
2.6)看个荔枝:(下面的程序创建了两个 Item 对象的树集, 第一个按照部件编号排序, 这是Item对象的默认顺序。第二个通过使用一个定制的比较器来按照描述信息排序-)
Complementary)我们给出 Integer 源码 的 Comparatable 实现:
java.lang.Comparable 1.2
int compareTo(T other) :将this 和 other 进行比较, 返回 正值、负值和0;
java.util.Comparator 1.2
int compare(T a, T b): 将a 和 b进行比较, 返回 正值、负值和0;
java.util.SortedSet 1.2
Comparator super E> comparator() :返回用于对元素进行排序的比较器, 如果元素用 Comparable 接口的compareTo 方法比较则返回 null;
E first();
E last();
返回有序集中的最小最大元素;
java.util.NavigableSet 6
E higher(E value)
E lower(E value)
返回大于 value 的最小元素或小于 value 的最大元素,否则返回 null;
E ceiling(E value)
E floor(E value)
返回大于等于 value 的最小元素或小于等于 value 的最大元素,否则返回 null;
E pollFirst(E value)
E pollLast(E value)
删除并返回这个集中的最大元素或最小元素, 这个集为空时返回 null;
Iterator descendingIterator():返回一个按照 递减顺序遍历集合中元素的迭代器;
java.util.TreeSet 1.2
TreeSet() :构造一个用于 排列 Comparable 对象的树集;
TreeSet(Comparator super E > c ):构造一个树集, 并使用指定的比较器对其中的元素进行排序;
TreeSet(SortedSet extends E> elements):构造一个树集, 将有序集中的所有元素添加到这个树集中, 并使用与给定集合相同的元素比较器;