java集合——树集(TreeSet)+对象的比较

【0】README

0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java集合——树集(TreeSet)+对象的比较 的相关知识;
0.2) for full source code, please visit https://github.com/pacosonTang/core-java-volume/blob/master/chapter13/TreeSetTest.java
0.3) for java.lang.Comparable 和 java.util.Comparator 的区别和联系:
http://blog.csdn.net/pacosonswjtu/article/details/50320775 + http://blog.csdn.net/pacosonswjtu/article/details/50320887


【1】树集(TreeSet)(用到了红黑树)

1.1)树集是一个有序集合。可以以任意顺序将元素插入到集合中, 在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现;

  • 1.1.1)看个荔枝:
SortedSet<String> 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)中慢, 但是,与将元素添加到数组或链表的正确位置上相比还是快很多的;
java集合——树集(TreeSet)+对象的比较_第1张图片
java集合——树集(TreeSet)+对象的比较_第2张图片
Attention) TreeSet 的排序功能用到了红黑树, 因此迭代器总是以排好序的顺序访问每个元素)

API java.util.TreeSet<E> 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<Item>
{
    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<Item>
{
    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<Item> set = new TreeSet<>(new 
    Comparable<Item>(){    //匿名 内部类;
     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)?
java集合——树集(TreeSet)+对象的比较_第3张图片

  • 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对象的默认顺序。第二个通过使用一个定制的比较器来按照描述信息排序-)
java集合——树集(TreeSet)+对象的比较_第4张图片
java集合——树集(TreeSet)+对象的比较_第5张图片


Complementary)我们给出 Integer 源码 的 Comparatable 实现:
java集合——树集(TreeSet)+对象的比较_第6张图片
java集合——树集(TreeSet)+对象的比较_第7张图片


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
ComparatorE> comparator() :返回用于对元素进行排序的比较器, 如果元素用 Comparable 接口的compareTo 方法比较则返回 null;
E first();
E last();
返回有序集中的最小最大元素;

java.util.NavigableSet<E> 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<E> descendingIterator():返回一个按照 递减顺序遍历集合中元素的迭代器;

java.util.TreeSet<E> 1.2
TreeSet() :构造一个用于 排列 Comparable 对象的树集;
TreeSet(ComparatorE > c ):构造一个树集, 并使用指定的比较器对其中的元素进行排序;
TreeSet(SortedSetE> elements):构造一个树集, 将有序集中的所有元素添加到这个树集中, 并使用与给定集合相同的元素比较器;

你可能感兴趣的:(java集合——树集(TreeSet)+对象的比较)