您的位置:首页 > 职场人生

黑马程序员:Java基础——Set集合之TreeSet

2014-10-26 17:42 831 查看
-------
Java EE培训、java培训、期待与您交流! ----------

1.概念

TreeSet:可以对Set集合中的元素进行排序

与HashSet方法一致,示例如下:

</pre><pre class="java" name="code">import java.util.Iterator;
import java.util.TreeSet;

import com.micronote.list.collection.SystemOutPrintClass;

public class TreeSetDemo extends SystemOutPrintClass{
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("nnzi");
ts.add("mjdk");
ts.add("njdi");
ts.add("nnnb");

for(Iterator it = ts.iterator();it.hasNext();){
sopln(it.next());
}
}
}

需要注意的是,我已经将打印的两种方法封装起来,让这个类继承SystemOutPrintClass就会出现sop()以及sopln()方法。

输出结果为:

mjdk

njdi

nnnb

nnzi

我们可以看到,TreeSet并没有按照我们输入的先后顺序进行排序,而是通过ASCII码进行排序。

2.扩展练习

同样的我们给TreeSet集合中填入自定义集合。要求也与前面的ArrayList相同。

根据这个我们编出代码,可是运行结果却是让我们诧异:



我们看到出现了ClassCastException,为什么呢?因为,我们传入的是对象,对象和对象并没有可比性,JVN不知道该怎么比较于是就抛出了异常。

我们找到Comparable接口:

Comparable是这样解释的:

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

接口里面只有一个方法——compareTo()返回类型为int型。

那么我们只需要让我们的对象类实现Comparable就可以实现重写compareTo方法了。

我们依照年龄排序,当年龄相同时在依照姓名排序:

@Override
public int compareTo(Object o) {
if(!(o instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s = (Student)o;

if(this.iAge-s.iAge!=0){
return this.iAge-s.iAge;
}else{
return this.sName.compareTo(s.sName);
}
}


当我们再次运行的时候,发现所有项目已经存进来而且去除了重复项。以下是完整代码:

import java.util.Iterator;
import java.util.TreeSet;

import com.micronote.list.collection.SystemOutPrintClass;

public class TreeSetTest extends SystemOutPrintClass{
public static void main(String[] args) {
TreeSet ts = new TreeSet();

ts.add(new Student("lisi001",21));
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi20",20));
ts.add(new Student("lisi021",21));
ts.add(new Student("lisi001",21));

for(Iterator it = ts.iterator();it.hasNext();){
Student stu = (Student)it.next();
sopln("Name:"+stu.getsName()+",Age:"+stu.getiAge());
}
}

}

class Student implements Comparable{

private String sName;
private int iAge;

Student(){}
Student(String sName,int iAge){
this.sName = sName;
this.iAge = iAge;
}

@Override public int compareTo(Object o) { if(!(o instanceof Student)){ throw new RuntimeException("不是学生对象"); } Student s = (Student)o; if(this.iAge-s.iAge!=0){ return this.iAge-s.iAge; }else{ return this.sName.compareTo(s.sName); } }

public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public int getiAge() {
return iAge;
}
public void setiAge(int iAge) {
this.iAge = iAge;
}
}

需要注意的是: 我的打印方法已经包装成了SystemOutPrintClass。以下是运行结果:

Name:lisi20,Age:20

Name:lisi001,Age:21

Name:lisi021,Age:21

Name:lisi02,Age:22

3.TreeSet的数据结构

通过上一节的例子,我们来看一下TreeSet的数据结构。TreeSet的底层数据结构是二叉树,存取方式如图所示:



我们把左边的Student对象依次存入TreeSet集合中,同样按照年龄排序,那么存储时小数存到左面,大数存到右面,以二叉的形式来存储数据。当读取时,会像图中蓝色数字顺序读取。那么我们看到的就是已经排过序的元素。

为了保证元素唯一性的依据;compareTo方法return 0.

TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。

4.实现Comparator方式排序

刚才说了TreeSet排序的一种方式,还有一种方式:

TreeSet排序的第二种方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。

在java.util包中有一个Comparator接口,这个接口强行对某个对象 collection 进行整体排序 的比较函数。

我们以上一节代码为基础,新建一个类,以下是全部代码:

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

import com.micronote.list.collection.SystemOutPrintClass;

public class TreeSetDemo2 extends SystemOutPrintClass{
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare());

ts.add(new Student("lisi001",21));
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi20",20));
ts.add(new Student("lisi021",21));
ts.add(new Student("lisi001",22));

for(Iterator it = ts.iterator();it.hasNext();){
Student stu = (Student)it.next();
sopln("Name:"+stu.getsName()+",Age:"+stu.getiAge());

}
}
}

class MyCompare implements Comparator{

@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student)o1;
Student s2 = (Student)o2;

int iNum = s1.getsName().compareTo(s2.getsName());
if(iNum!=0){
return iNum;
}else{
return new Integer(s1.getiAge()).compareTo(new Integer((s2.getiAge())));
/*if(s1.getiAge()!=s2.getiAge()){
return s1.getiAge()-s2.getiAge();
}else{
return 0;
}*/
}
}
}


运行结果如下:

Name:lisi001,Age:21

Name:lisi001,Age:22

Name:lisi02,Age:22

Name:lisi021,Age:21

Name:lisi20,Age:20

通过运行我们发现:

定义了比较器,将比较其对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。我们可以这么理解,集合也调用过Comparable进行了排序,后来又被Comparator的排序覆盖掉了。

定义一个类,实现Comparator接口,覆盖compare方法。

5.TreeSet练习

练习:按照字符串长度排序。

分析:字符串本身具备比较性,但是它的比较方式不是所需要的。

使用Comparator会更方便

代码一:

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

import com.micronote.list.collection.SystemOutPrintClass;

public class TreeSetTest2 extends SystemOutPrintClass{
public static void main(String[] args) {
TreeSet ts = new TreeSet(new CompareStrLength());
ts.add("abcd");
ts.add("cc");
ts.add("bcdef");
ts.add("bb");
ts.add("cde");
ts.add("defghi");

for(Iterator it = ts.iterator();it.hasNext();){
sopln(it.next());
}
}
}

class CompareStrLength implements Comparator{

@Override
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;

int iNum = new Integer(s1.length()).compareTo(s2.length());
if(iNum==0){
return s1.compareTo(s2);
}else{
return iNum;
}
}
}

代码二(匿名内部类);

import java.util.Comparator;

import java.util.Iterator;

import java.util.TreeSet;

import com.micronote.list.collection.SystemOutPrintClass;

public class TreeSetTest3 extends SystemOutPrintClass {

public static void main(String[] args) {

TreeSet ts = new TreeSet(new Comparator() {

@Override

public int compare(Object o1, Object o2) {

String s1 = (String) o1;

String s2 = (String) o2;

int iNum = new Integer(s1.length()).compareTo(s2.length());

if (iNum == 0) {

return s1.compareTo(s2);

} else {

return iNum;

}

}

});

ts.add("abcd");

ts.add("cc");

ts.add("bcdef");

ts.add("bb");

ts.add("cde");

ts.add("defghi");

for (Iterator it = ts.iterator(); it.hasNext();) {

sopln(it.next());

}

}

}

运行结果为:

bb

cc

cde

abcd

bcdef


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: