学习笔记之JavaSE(33)--JavaAPI详解8

今天学习的内容是集合类之TreeSet


TreeSet的底层数据结构是二叉树,是不同步的。与HashSet不同,TreeSet是有序的,准确来说TreeSet可以按照指定规则对元素进行排序注意由于TreeSet中的元素要按照制定规则进行排序,所以TreeSet不能存储null


那么TreeSet是如何进行排序的呢?有两种方法:

  1. 自然排序元素所属的类实现Comparable接口,并实现其compareTo()方法,排序规则即为compareTo()方法的内容。在存储元素时,TreeSet会调用该元素的compareTo()方法与集中其它元素进行比较,如果该元素小于、等于或大于指定元素,则分别返回负整数、零或正整数,如果返回零即认为两元素重复,不会存储该元素,如果返回负整数或正整数则会将该元素存储在与之比较的元素的前面或后面。JavaAPI中大部分类都实现了Comparable接口并实现了其compareTo()方法,比如包装类和String类
  2. 比较器排序定义一个实现了Comparator接口的比较器,并实现其compare()方法,排序规则即为compare()方法的内容,最后将其实例作为TreeSet构造函数的参数传入集中。在存储元素时,TreeSet会调用比较器的compare()方法将该元素与集中其它元素进行比较,比较结果与排序原则同上。如果某元素所属的类不具备自然排序,或者不想使用该类的自然排序,就可以使用比较器排序(实际开发中这种情况比较多见,所以比较器排序比较常用),注意比较器排序的优先级高于自然排序
PS:如果想让元素添加顺序排序也很简单,令compareTo()方法或compare()方法的返回值恒为正整数即可。


关于TreeSet两种比较方式的示例程序:

public class Test57 {

	public static void main(String[] args) {

		// 基本用法
		TreeSet<String> set = new TreeSet<>();
		set.add("b");
		set.add("c");
		set.add("a");
		set.add("a");
		System.out.println(set);// [a, b, c] String类本身就实现了Comparable接口的compareTo()方法
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			String str = it.next();
			System.out.println(str);
		}

		// 使用自然排序
		TreeSet<Person> ts = new TreeSet<>();
		ts.add(new Person("zhangsan", 21));
		ts.add(new Person("lisi", 22));// 如果Person类没有实现Comparable接口,会发生ClassCastException
		ts.add(new Person("wangwua", 23));
		ts.add(new Person("wangwub", 23));
		ts.add(new Person("zhaoliu", 24));
		System.out.println(ts);// [Person [name=zhangsan, age=21], Person
								// [name=lisi, age=22], Person [name=wangwua,
								// age=23], Person [name=wangwub, age=23],
								// Person [name=zhaoliu, age=24]]
		Iterator<Person> it_p = ts.iterator();
		while (it_p.hasNext()) {
			Person p = it_p.next();
			System.out.println(p);// 按照年龄进行从小到大排序,如果年龄相等,再按照姓名进行自然排序
		}

		// 使用比较器排序
		TreeSet<Person> ts_com = new TreeSet<>(new ComparatorByName());
		ts_com.add(new Person("zhangsan", 21));
		ts_com.add(new Person("lisi", 22));
		ts_com.add(new Person("wangwu", 23));
		ts_com.add(new Person("wangwu", 24));
		ts_com.add(new Person("zhaoliu", 24));
		System.out.println(ts_com);// [Person [name=lisi, age=22], Person
									// [name=wangwu, age=23], Person
									// [name=wangwu, age=24], Person
									// [name=zhangsan, age=21], Person
									// [name=zhaoliu, age=24]]
		Iterator<Person> it_com = ts_com.iterator();
		while (it_com.hasNext()) {
			Person p = it_com.next();
			System.out.println(p);// 按照姓名进行自然排序,如果姓名相同,再按照年龄大小进行排序
		}
	}
}

class Person implements Comparable<Person> {

	private String name;
	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() { // 覆盖Object的hashCode()方法
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {// 覆盖Object的equals()方法
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

	// 本例中按照年龄进行从小到大排序,如果年龄相等,再按照姓名进行自然排序
	@Override
	public int compareTo(Person o) {

		int temp = this.age - o.age;
		return temp == 0 ? this.name.compareTo(o.name) : temp;
	}
}

// 自定义比较器,按照姓名进行自然排序,如果姓名相同,再按照年龄大小进行排序
class ComparatorByName implements Comparator<Person> {

	@Override
	public int compare(Person o1, Person o2) {

		int temp = o1.getName().compareTo(o2.getName());
		return temp == 0 ? o1.getAge() - o2.getAge() : temp;
	}
}

实际开发中很有可能 不想使用某类的自然排序,但又无法修改该类,这时候就可以使用比较器排序,由于比较器排序的优先级要高于自然排序,所以排序规则使用的是compare()方法中的内容,如下例:

public class Test58 {

	public static void main(String[] args) {

		TreeSet<String> ts = new TreeSet<>(new ComparatorByStringLength());
		ts.add("abc");
		ts.add("cba");
		ts.add("zzqz");
		ts.add("aaaqw");
		ts.add("nba");
		System.out.println(ts);// [abc, cba, nba, zzqz, aaaqw]
	}

}

// 按照字符串长度进行排序,如果长度相同,按照字符串的自然顺序进行排序
class ComparatorByStringLength implements Comparator<String> {

	@Override
	public int compare(String o1, String o2) {

		int temp = o1.length() - o2.length();
		return temp == 0 ? o1.compareTo(o2) : temp;
	}
	
}


总结:如果要按照特定规则对元素进行排序,建议使用TreeSet;如果想让元素按照添加顺序排序,建议使用LinkedHashSet;其他情况都使用HashSet

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值