Java基础16--集合框架(四)

2014-11-24 07:32:11 · 作者: · 浏览: 2
序的。

例如:

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即可。