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

------- 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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值