例如:
public class LinkedHashSetDemo {
public static void main(String[] args) {
HashSet hs = new LinkedHashSet();
hs.add("haha");
hs.add("hehe");
hs.add("heihei");
hs.add("xixi");
Iterator it = hs.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:haha hehe heihei xixi
输入和输出顺序是相同的。
16-10,TreeSet集合
1,这个集合可以对Set集合中的元素进行指定顺序的排序(按自然顺序进行排序)。
例如:
TreeSet ts = new TreeSet();
ts.add("zhangsan",22);
ts.add("lisi",23);
ts.add("wangwu",27);
迭代...
发现第二个ts.add报错。
原来,TreeSet要进行排序,就必须要具备排序这个功能,就Person来说,排序功能如何实现呢?
应该用java.lang中的Comparable接口,Person要想具备排序功能,实现Comparable接口即可。
Comparable接口的描述:
此接口强行对实现它的每一个类的对象进行整体排序,这种排序被称为类的自然排序,类的compareTo方法被称为他的自然比较方法。
2,TreeSet判断对象唯一性的方式,就是根据比较方法的返回结果是否为0,是0,就是相同元素,不存进去。在示例中,如果Person实现了Comparable接口并重写了compareTo方法,并且其返回0,则再运行时不会报错,但是只会打印出存的第一个元素,即:zhangsan,22,因为要存第二个的时候,会调用compareTo方法判断是否与上一个元素相同,由于返回结果是0,即表示相同,所以后面的元素就都不往里存了,所以只打印第一个元素。
3,以Person对象的年龄进行从小到大的排序。
将上面的Person类实现Comparable接口,然后在Person中覆写compareTo方法。
//若要按照从大到小排序,把1变为-1,把-1变为1即可,或把this变为p,把p变为this.
public int compareTo(Object obj) {
Person p = (Person)obj;
if(this.age > p.age)
return 1;
if(this.age < p.age)
return -1;
return 0;
}
但是如果年龄相同,则后一个就打印不出来了,即:打印时少了一个Person。
这时应该加条件,如果主要条件相同,则应该比较次要条件。
修改后的compareTo方法:
public int compareTo(Object obj) {
Person p = (Person)obj;
if(this.age > p.age)
return 1;
if(this.age < p.age)
return -1;
else
/*
String类中的compareTo方法也来自于Comparable接口,
String类实现了Comparable接口
*/
return this.name.compareTo(p.name);
}
但是这么写烂透了...,优化:
public int compareTo(Object obj) {
Person p = (Person)obj;
int temp = this.age - p.age;
return temp == 0 this.name.compareTo(p.name) : temp;
}
之前在TreeSet中存String类的对象,可以进行排序,是因为String类实现了Comparable接口。
总结:TreeSet对元素进行排序的方式之一:
让元素自身具备比较功能,元素需要实现Comparable接口,覆盖compareTo方法。
16-11,TreeSet集合,Comparator比较器
1,如果不要按照对象中具备的自然顺序,如果对象中不具备自然顺序,怎么办?
可以使用TreeSet的第二种排序方式:让集合自身具备比较功能。
2,TreeSet的构造器中有一个带有Comparator参数的构造器,在创建TreeSet对象时传入此Comparator的对象,该TreeSet可按指定的Comparator比较器进行排序。
3,java.util
接口:Comparator
强行对某个对象Collection进行整体排序的比较函数。
4,单独创建一个Java文件,创建一个根据Person类的name进行排序的比较器。
public class ComparatorsByName implements Comparator {
public int compare(Object o1,Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp == 0 p1.getAge() - p2.getAge() : temp;
}
}
然后,在创建TreeSet集合的时候,直接:
TreeSet ts = new TreeSet(new ComparatorsByName());
即可。
5,如果Person对象本身实现了Comparable接口,覆盖了compareTo方法,而且把Person对象存入了已经实现了比较器的TreeSet中,那么以谁的比较功能为主呢?
以比较器的功能为主,且实际开发中比较器比较常用。
实际上Java中的很多类都实现了Comparable接口,使其对象具备比较功能。
6,使集合自身具备比较功能的步骤:
定义一个类实现Comparator接口,覆盖compare方法,将该类对象作为参数传递个TreeSet集合的构造函数。
16-12,TreeSet-二叉树
1,TreeSet排序功能在底层是如何实现的呢?
他的排序功能在底层是通过二叉树来实现的。
以下列TreeSet的添加为例,用图表示(根据Person的age排序),
第一个进去的元素不用进行比较,以后进去的元素都要与前面的元素比较。
步骤:
第一个28进来以后,发现前面没有元素,不做比较,直接放在第一个位置。
21进来后,跟28比较,比28小,放在28的左边。
29进来后先跟28比较,比28大,放在28的右边,就不用和21比较了。
25进来后先跟28比较,比28小,到左边,再跟21比较,比21大,则放在21的右边。
......
在树中,每个节点都有自己的属性,以值为21的节点举例:
21有三个引用,分别记录与之链接的父节点,以及左子节点和右子节点,以记录整个集合各个元素的位置,但28没有父,19没有左和右。
但是树的规模一大,就涉及到效率问题,如何解决呢?
其实,只要树一排完,该集合就已经是一个有序的集合了,有序集合的查找,就可以想到用二分查找法。
其实每次向里面添加元素的时候,都会对已有的元素进行折半,二分查找,以确定新元素的位置,效率较高。
2,如何做到怎么存就怎么取的呢
直接在比较器中返回1就行了,这样可以保证后进来的元素经比较后总是大于前面的元素,如果要倒序取出的话,直接返回一个-1即可。