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 。
相关推荐
一条上岸小咸鱼6 小时前
Flutter 类和对象(二):继承
android·kotlin
针叶6 小时前
解决Android Studio查找aar源码的错误
android·gradle·android studio
2501_916008897 小时前
uni-app iOS 应用版本迭代与上架实践 持续更新的高效流程
android·ios·小程序·https·uni-app·iphone·webview
人生游戏牛马NPC1号8 小时前
学习 Android (十八) 学习 OpenCV (三)
android·opencv·学习
zhangphil9 小时前
Android把源Bitmap中心缩放到固定宽高的尺寸,Kotlin
android·kotlin
2501_915909069 小时前
uni-app iOS 性能监控与调试全流程:多工具协作的实战案例
android·ios·小程序·https·uni-app·iphone·webview
魔鬼辣不够辣9 小时前
ADB图片上传轮播
android·adb·kotlin
踏雪羽翼10 小时前
Android 16k页面大小适配
android
用户0910 小时前
Kotlin后端开发指南
android·后端