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

2022-08-07,,,

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


文章目录

    • TreeSet
      • TreeSet存储自定义对象
        • Comparable接口
        • 定义Dog类实现Comparable接口
      • 比较器
        • Comparator接口的方法
        • 实现Comparator方法的案例
      • TreeSet原理

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

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

下载本文的Word格式文档,以方便收藏与打印。