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 。
相关推荐
拥小抱3 小时前
Compose 知识点
android
文章永久免费只为良心3 小时前
Web应用安全与防护_第三章_日志文件包含_从一道 CTFshow 题目讲透「日志投毒型 LFI → RCE」:原理、时序陷阱与全变种攻防手册
android·网络安全·渗透测试·漏洞危害·漏洞描述·日志投毒·红队指南
AIsoft_86893 小时前
学术讲座录音如何整理?录音APP可行吗
android·iphone
Patrick在香港6 小时前
一个斜杠,把毫秒变成十几秒
android·数据库·python·性能优化·正则表达式·回溯·redos
海雅达手持终端PDA7 小时前
工业手持终端的“去手机化”演进:看海雅达如何以“同轴扫摄”终结工程妥协,重塑工业PDA新范式
android·物联网·智能手机·硬件工程·能源·制造·iot
booboosui8 小时前
删掉一个住在本机的 agent:8 处要清,顺序不能反
android
hcgeng8 小时前
Android获取崩溃日志
android
aqi009 小时前
AI编程让鸿蒙开发电子书APP更加快捷
android·华为·harmonyos·鸿蒙·harmony
GY-939 小时前
【Android】Android Studio 中的协程
android