TreeSet原理

特点

  • TreeSet 底层是采用 TreeMap 实现的一种 Set 集合;
typescript 复制代码
//和HashSet一样,PRESENT的目的是为了占位
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return this.m.put(e, PRESENT) == null;
}
  • 单线程安全,多线程不安全;
  • 使用无参构造器创建TreeSet时,是无序的(存入取出顺序不一致);
csharp 复制代码
public TreeSet() {
    this((NavigableMap)(new TreeMap()));
}
  • 如果需要排序,需要指定排序规则
java 复制代码
/**
 * 有参构造函数
 * 使用带 comparator 的 TreeMap 初始化
 * @param comparator 比较器
 */
public TreeSet(Comparator<? super E> comparator) {
    this((NavigableMap)(new TreeMap(comparator)));
}

TreeSet 在存对象的时候,如果不指定自定义的比较器,那么存储的对象必须实现 Comparable 接口,以Integer类为例:

java 复制代码
public final class Integer extends Number implements Comparable<Integer> {
	
	//省略其他代码
	//......
	public int compareTo(Integer anotherInteger) {
	    return compare(this.value, anotherInteger.value);
	}
	
	public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
}

TreeSet 底层插入元素的过程简述

TreeSet(TreeMap)底层是二叉树实现的,当存储元素的时候,会调用比较规则方法,将新元素和二叉树上已有的元素进行一一比较。

  • 如果要插入的元素比当前元素小、就到左子树去比较;
  • 如果比当前元素大,就到右子树去比较,直到当前元素的左或者右子树为空,就插入此元素;
  • 如果在比较过程中,出现当前元素等于要插入的元素,那么此元素不插入;

注意:基本数据类型,不需要定义比较器,只有当以树作为存储结构时,而且添加的是引用对象时,才需要定义比较器;

定义比较器的方式有两种:

实现 内部比较器Comparable 接口
typescript 复制代码
public class Student implements Comparable<Student>{
	private String name;
	private int age;
	
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
    //按照学生年龄排序
	@Override
	public int compareTo(Student o) {
		return this.age - o.age;
	}
}

实现 Comparable 接口的类必须实现 compareTo(Object obj) 方法,两个对象通过 compareTo 方法的返回值来比较大小 :

  • 如果当前对象 this 大于形参对象 obj 则返回正整数;
  • 如果当前对象 this 小于 形参对象 obj则返回 负整数;
  • 如果当前对象 this 等于 形参对象 obj 则返回零;
自定义外部比较器Comparator接口
csharp 复制代码
public class DemoTreeSet {
	public static void main(String[] args) {
        //匿名内部类实现比较器:首先按照年龄进行排序,如果年龄相同,我们再按照名字的长度进行排序(升序)
		TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
			@Override
			public int compare(Student o1, Student o2) {
				int num = o1.getAge() - o2.getAge();
				return num == 0 ? o1.getName().length() - o2.getName().length() : num;
			}
		});
		ts.add(new Student("张廷玉",43));
		ts.add(new Student("纳兰明珠",80));
		ts.add(new Student("索额图",79));
		ts.add(new Student("苏麻喇姑",79));
		for (Student student : ts) {
			System.out.println(student);
		}
	}
}

通过new一个匿名内部类的方式,定义一个外部比较器Comparator接口对象,重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小:

  • 如果方法返回正整数,则表示 o1 大于 o2 ;
  • 如果方法返回 0 ,表示相等;
  • 如果方法返回负整数,表示o1 小于 o2 。
相关推荐
用户20187928316719 分钟前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子19 分钟前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜822728 分钟前
安卓接入Max广告源
android
齊家治國平天下28 分钟前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO28 分钟前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel31 分钟前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢36 分钟前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱
IT酷盖36 分钟前
Android解决隐藏依赖冲突
android·前端·vue.js
努力学习的小廉2 小时前
初识MYSQL —— 数据库基础
android·数据库·mysql
风起云涌~2 小时前
【Android】浅谈androidx.startup.InitializationProvider
android