TreeSet是Set接口的另一个实现类,它使用自平衡排序二叉树在内部存储元素。 这样的结构使您可以对元素进行排序,而在TreeSet集合中没有重复的元素。 二叉树是指各节点最多具有2个子节点的顺序树,由各节点及其子节点构成的树称为子树,通常左侧的子节点称为“左子树”,右侧的子节点称为“右子树”。 二叉树中要素的存储结构如图所示。
在实际应用中,二叉树可分为许多种类,如对二叉树进行排序、平衡二叉树等。 TreeSet集合内部使用自平衡排序二叉树。 其特征是,保存的元素按大小排序,可以删除重复的元素。 例如,在一个二叉树中按照13、8、17、17、1、11、15、25的顺序存储8个要素,将二叉树进行排序存储时,如图所示,集合内的存储结构形成树结构。
从图中可以看出,在TreeSet集合中依次收纳要素时,首先将最初收纳的要素放在二叉树的最上面,将之后收纳的要素与最初的要素进行比较,如果比最初的要素小,则将该要素放在左边的部分树上,如果比第1个要素大,则将该要素放在右边的部分树上,依此类推二叉树中已经有17个要素的情况下,集合中有17个要素的情况下,TreeSet会去除重复的要素。
既然了解了二叉树存储元素的原理,我们将在一个案例中展示TreeSet对元素的排序效果,如下例所示。 importjava.util.Iterator;
importjava.util.TreeSet;
公共类扩展{
publicstaticvoidmain (字符串[ ] args ) {
TreeSetts=newTreeSet (; 创建TreeSet集合
ts.add(jack ); 将元素添加到TreeSet集合
ts.add(Helena );
ts.add(Helena );
ts.add(Eve );
Iteratorit=ts.iterator (; 获取迭代器对象
while(it.Hasnext ) ) ) )。
system.out.println(it.next ) );
}
}
}
执行结果: Eve
埃琳娜
杰克
如图所示,迭代器重复的字符串元素按字母顺序打印。 这些元素之所以可以排序,是因为每次将元素存储在TreeSet集合中时,都会将它们与其他元素进行比较,最后插入到有序的对象序列中。 比较集合中的元素时,将调用compareTo ()方法。 此方法是在Comparable接口中定义的,因此必须实现Comparable接口才能对集合中的元素进行排序。 JDK中的大多数类都实现了Comparable接口,并具有Integer、Double、String等接口中的CompareTo )方法。
在TreeSet集合中存储Student类型的对象时,如果Student类没有实现Comparable接口,则无法比较Student类型的对象。 此时,TreeSet集合不知道按什么排序规则对Student对象进行排序,并最终报告程序错误。 因此,要在TreeSet集合中存储Student对象,必须在Student类中实现Comparable接口,如示例所示。 importjava.util.Iterator;
importjava.util.TreeSet;
classtudentimplementscomparable//定义student类实现comparable接口
字符串名称;
输入;
公共结构(string name,intage ) )//创建构造方法
this.name=name;
this.age=age;
}
重写publicStringtoString () Object类的toString )方法,并返回描述信息
返回名称' : ' age;
}
重写公共计算机(objectobj )计算机接口的计算机方法
sudents=(student ) obj; //将比较对象改为Student型
if(this.age-s.age0) )//定义比较方式
返回1;
}
if(this.age-s.age==0) {
return this.name.com Pareto (s.name ); //返回比较结果
}
回退
rn -1;}
}
public class Example {
public static void main(String[] args) {
TreeSet ts = new TreeSet(); // 创建TreeSet 集合
ts.add(new Student("Jack", 19)); // 向集合中添加元素
ts.add(new Student("Rose", 18));
ts.add(new Student("Tom", 19));
ts.add(new Student("Rose", 18));
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
运行结果:Rose:18
Jack:19
Tom:19
例中,Student 类实现了Comparable 接口中的compareTo()方法。在compareTo()方法中,首先先针对age值进行比较,根据比较结果返回-1和1,当age相同时,再对name进行比较。因此,从运行结果可以看出,学生首先按照年龄排序,年龄相同时会按照姓名排序。
有时候,定义的类没有实现Comparable接口或者实现了Comparable接口而不想按照定义的compareTo()方法进行排序。例如,希望字符串可以按照长度来进行排序,这时,可以通过自定义比较器的方式对TreeSet集合中的元素排序,即实现Comparator接口,在创建TreeSet集合时指定比较器。接下来通过一个案例来实现TreeSet集合中字符串按照长度进行排序,如例所示。import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
class MyComparator implements Comparator { // 定义比较器实现Comparator 接口
public int compare(Object obj1, Object obj2) { // 实现比较方法
String s1 = (String) obj1;
String s2 = (String) obj2;
int temp = s1.length() - s2.length();
return temp;
}
}
public class Example {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyComparator()); // 创建TreeSet 对象时传入自定义比较器
ts.add("Jack"); // 向该Set 对象中添加字符串
ts.add("Helena");
ts.add("Eve");
Iterator it = ts.iterator(); // 获取Iterator 对象
// 通过while 循环,逐渐将集合中的元素打印出来
while (it.hasNext()) {
// 如果Iterator 有元素进行迭代,则获取元素并进行打印
Object obj = it.next();
System.out.println(obj);
}
}
}
运行结果:Eve
Jack
Helena
例中,定义了一个MyComparator类实现了Comparator接口,在compare()方法中实现元素的比较,这就相当于定义了一个比较器。在创建TreeSet集合时,将MyComparator比较器对象传入,当向集合中添加元素时,比较器对象的compare()方法就会被自动调用,从而使存入TreeSet集合中的字符串按照长度进行排序。