读书人

黑马软件工程师_集合学习之treeSet

发布时间: 2013-04-09 16:45:09 作者: rapoo

黑马程序员_集合学习之treeSet

TreeSet与HashSet

由于内部数据结构不同,判断元素重复的条件也不同,

HashSet是判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals是否为真。

TreeSet

我们用如下的例子体现:

TreeSet<String>ts = new TreeSet<String>();

ts.add("aaa");

ts.add("ddd");

ts.add("eee");

ts.add("bbb");

for(Strings:ts)

{

System.out.println(s);

}

结果:

aaa

bbb

ddd

eee

说明TreeSet可以按一定顺序(自然的顺序)进行排序。这也是它最大的特点。

之后存一些自定义的对象。

classStudent

{

privateStringname;

privateintage;

publicStudent(String name,int age) {

super();

this.name =name;

this.age =age;

}

publicString getName() {

returnname;

}

publicvoidsetName(String name) {

this.name =name;

}

publicintgetAge() {

returnage;

}

publicvoidsetAge(int age) {

this.age =age;

}

}

TreeSet<Student>ts = new TreeSet<Student>();

ts.add(newStudent("001",1));

ts.add(newStudent("003",2));

ts.add(newStudent("002",3));

ts.add(newStudent("004",4));

运行抛出异常。

原因是这个对象不具备比较性。

。。。。

TreeSet要求存入的元素具有比较性,怎么才能有比较性?

要 实现一个comparable接口。并实现其中的方法。就具有了比较性。

把相应的方法加入到student中

publicintcompareTo(Object o)

{

Student s = (Student)o;

System.out.println(this.name+"compareTo"+s.name);

returnthis.age-s.age;

}

publicString toString()

{

returnthis.name+"..."+this.age;

}

再一次的调用

TreeSet<Student>ts = new TreeSet<Student>();

ts.add(newStudent("001",1));

ts.add(newStudent("003",2));

ts.add(newStudent("002",3));

ts.add(newStudent("004",4));

System.out.println(ts);

输出

003compareTo001

002compareTo001

002compareTo003

004compareTo003

004compareTo002

[001...1,003...2, 002...3, 004...4]

则说明正好是treeset底层调用了比较函数去进行了一系列的比较。

并最终排好了序(根据compareTo中特殊的比较方式排序)。。

但是。当出现

ts.add(newStudent("009",4));

时候,由于年龄一致

所以输出

[001...1,003...2, 002...3, 004...4]

009没有被存入。

所以必须要判断一下姓名。

publicintcompareTo(Object o)

{

Student s = (Student)o;

System.out.println(this.name+"compareTo"+s.name);

if(this.age==s.age)

return this.name.compareTo(s.name);

returnthis.age-s.age;

}

这样,只有年龄和姓名一致后,才不被存入集合中,当年龄不一样时候,用年龄排序

当年龄一致。则使用姓名进行排序。

则输出

[001...1,003...2, 002...3, 004...4, 009...4]

所以要记住,在对自定义的对象排序时候,先对主要条件进行排序后,再对次要条件进行排序。

下面,我们来看一看treeSet的内部实现机制。

底层使用了一个特殊的数据结构。

就使用上边的例子





上述图的得出分析


4存入,

2进来,与4进行比较,小于4,放在左边。

3进来,与4比较,在左,与2比较,大于2,故放在2的右边

1进来,与4比较,在左,与2比较,小于2,故放在2的左边。

也就是底层实现了一个二叉树。从而避免了加入一个元素的时候和集合中的每个元素

进行比较。提高了比较 性能。

那么如何进行取元素呢?

按照定义的比较顺序去取,比如从小到大。

那么先去左子树的最左边的值。往上依次走。

有一个问题,想要是元素按原来的排序逆序输出呢?千万不要用

returnthis.age-s.age;置换这里的this和s

而是用java中有其他的特殊的方式去实现。

对于TreeSet来说,它只用compareTo去看是负数,0,正数,而与其他方法无关。

始终使用默认的比较的(小----->大)去存储和输出数据。

也就是无论使用什么比较方式,都是按其比较的最小------》最大去对元素进行排序。

也就是从二叉树的最左端到二叉树的最右端进行比较。

综上所述:

TreeSet可以对set集合中的元素进行排序。底层的数据结构是二叉树。保证元素唯一性的依据叫做compareTo()方法return 0;与hashcode没有关系。与equals也没有关系。TreeSet排序的第一种方式,让元素自身具备了比较性。元素需要实现comparable接口覆盖compareTo方法。这种方式也称为元素的自然顺序,也叫做默认顺序。

这时,我们就考虑一个问题,当元素真的不具备比较性的时候,应该怎么办?

也就是不能实现comparable接口和其中的compareTo();

还有,你实现的比较方式和现在的需求不符合了,去强制改变类中的方法也是不现实的。

这就有了TreeSet的第二种排序方式。

这时就需要让集合自身具备比较性。

让容器去决定元素哪个大或小,也就是两个人去找集合,让集合去比较二个人,而不是两个人相互的去比较。

也就是在集合一初始化的时候,就有了比较的方式。

TreeSet(Comparator<? superE> comparator)
构造一个新的空 TreeSet,它根据指定比较器进行排序。

就用到了这个构造函数。

比方说,需求是按照姓名排序,而上边是按照年龄优先排序

classMyCompimplementsComparator

{

publicintcompare(Object o1,Object o2)

{

Student s1 = (Student)o1;

Student s2 = (Student)o2;

returns1.getName().compareTo(s2.getName());

}

}

就使用上边的方式去创建一个本身具备比较的集合。

当集合自身具备比较性质和对象也具有比较性质的时候,优先使用集合自身的比较方法。也就是以比较器为主。

比较器比较常用一些。

以return 0 来确定元素是否存在。



读书人网 >编程

热点推荐