欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

第三次学JAVA再学不好就吃翔(part90)--TreeSet

程序员文章站 2022-04-29 10:48:43
学习笔记,仅供参考,有错必纠文章目录TreeSetTreeSet存储自定义对象Comparable接口定义Dog类实现Comparable接口比较器Comparator接口的方法实现Comparator方法的案例TreeSet原理TreeSet该类基于TreeMap的 NavigableSet 实现,使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的Comparator进行排序,具体取决于使用的构造方法。举个例子package com.guiyang.restudy3...

学习笔记,仅供参考,有错必纠




TreeSet


该类基于TreeMap的 NavigableSet 实现,使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的Comparator进行排序,具体取决于使用的构造方法。


  • 举个例子
package com.guiyang.restudy3;

import java.util.TreeSet;

public class D3TreeSet {

	public static void main(String[] args) {
		TreeSet<Integer> ts = new TreeSet<>();
		ts.add(3);
		ts.add(1);
		ts.add(1);
		ts.add(2);
		ts.add(2);
		ts.add(3);
		ts.add(3);	
		System.out.println(ts);
	}
}

输出:

[1, 2, 3]

TreeSet存储自定义对象


Comparable接口


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


  • compareTo方法
int compareTo(T o)

比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。


定义Dog类实现Comparable接口


现在,我们构造Dog类,并实现Comparable接口,并重写compareTo方法:

package com.guiyang.eclipse;

public class Dog implements Comparable<Dog>{

	private String name;
	private int age;
	
	public Dog(String name, int age) {
		this.name = name;
		this.age = age;
		
	}
	
	public Dog() {}

	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 int compareTo(Dog o) {
		
		return 0;
		//return 1; 
		//return -1;
	}
    
	@Override
	public String toString() {
		return "<name:" + name + ", age:" + age + ">";
	}
}

需要注意的是,当compareTo方法返回值恒为0的时候,TreeSet集合中只有一个元素,当compareTo方法返回值恒为正数(比如1)时,TreeSet集合会怎么存就怎么取,当compareTo方法返回值恒为负数时(比如-1),TreeSet集合会按照倒序存储。


我们按照age和name的大小,重写compareTo方法:

@Override
public int compareTo(Dog o) {
int num = this.age - o.age;
return num == 0 ? this.name.compareTo(o.name) : num;
//上述代码表示,年龄相同比较name,不相同则返回num
//String类已经对compareTo方法进行了重写,返回一个int值
}

现在我们用TreeSet存储自定义Dog类:

package com.guiyang.restudy3;

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

import com.guiyang.eclipse.Dog;


public class D4TreeSetDog {

	public static void main(String[] args) {
		TreeSet<Dog> ts = new TreeSet<>();
		ts.add(new Dog("Huang", 9));
		ts.add(new Dog("Black", 10));
		ts.add(new Dog("Pink", 5));
		ts.add(new Dog("Green", 10));
		ts.add(new Dog("Huang", 12));
		
		System.out.println(ts);
	}
}

输出:

[<name:Pink, age:5>, <name:Huang, age:9>, <name:Black, age:10>, <name:Green, age:10>, <name:Huang, age:12>]

比较器


我们看一个TreeSet的有参构造方法:

TreeSet(Comparator<? super E> comparator) 

构造一个新的空TreeSet,它根据指定的比较器进行排序。


这个Comparator是一个接口,我们不能直接创建其对象,而需要先构造它的子类去实现该接口,并重写接口里的方法。


Comparator接口的方法


  • compare方法
int compare(T o1, T o2)

比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。


  • equals方法
boolean equals(Object obj)

指示某个其他对象是否"等于"此 Comparator,仅当指定的对象也是一个 Comparator,并且强行实施与此 Comparator 相同的排序时,此方法才返回 true。因此,comp1.equals(comp2) 意味着对于每个对象引用 o1 和 o2 而言,都存在 sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2))


实现Comparator方法的案例


package com.guiyang.restudy3;

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

public class D4TreeSetDog {

	public static void main(String[] args) {
		//将字符串按照长度排序
		TreeSet<String> ts = new TreeSet<>(new CompareByLen());		//Comparator c = new CompareByLen();
		ts.add("aaaaaaaa");
		ts.add("bbb");
		ts.add("ddddd");
		ts.add("aaa");
		ts.add("e");
		
		System.out.println(ts);

	}
}

class CompareByLen implements Comparator<String> {
	//默认继承Object类,Object类中已经重写了equels方法

	@Override
	public int compare(String s1, String s2) {		//按照字符串的长度比较
		int num = s1.length() - s2.length();		//长度为主要条件
		return num == 0 ? s1.compareTo(s2) : num;	//内容为次要条件
	}
}

输出:

[e, aaa, bbb, ddddd, aaaaaaaa]

TreeSet原理


TreeSet是用来排序的,可以指定一个顺序, 对象存入之后会按照指定的顺序排列,这两种顺序分别为自然顺序和比较器顺序。


  • 自然顺序(Comparable)
    • TreeSet类的add()方法中会把存入的对象提升为Comparable类型
    • 调用对象的compareTo()方法和集合中的对象比较
    • 根据compareTo()方法返回的结果进行存储
  • 比较器顺序(Comparator)
    • 创建TreeSet的时候可以制定 一个Comparator
    • 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
    • add()方法内部会自动调用Comparator接口中compare()方法排序
    • 调用的对象是compare方法的第一个参数,集合中已添加的对象是compare方法的第二个参数
  • 两种方式的区别
    • 在TreeSet构造方法中,如果什么都不传, 默认按照类中Comparable的规则进行比较(若该类没有实现Comparable类,就会报出ClassCastException错误)
    • 在TreeSet构造方法中,如果传入Comparator, 就优先按照Comparator的规则进行比较

本文地址:https://blog.csdn.net/m0_37422217/article/details/107270494