TreeSet底层add及例题 day14
package com.shujia.day14;
import java.util.TreeSet;
/*
Collection:
- List(元素有序且可以发生重复,有索引的概念)
- ArrayList(底层数据结构是数组,查询快,增删慢,线程不安全,效率高)
- Vector(底层数据结构是数组,查询快,增删慢,线程安全,效率低,即便安全,我们今后也不用)
- LinkedList(底层数据结构是双链表,增删快,查询慢,线程不安全,效率高)
- Set(元素唯一且无序)
- HashSet(底层数据结构是哈希表,线程不安全,效率高,要求元素类中要重写hashCode和equals方法,才能保证唯一)
- LinkedHashSet(底层数据结构是哈希表和双链表,哈希表保证了元素的唯一性,双链表保证了元素的有序)
- TreeSet(底层数据结构是红黑树)
两种排序方式:
1. 自然排序
使用无参构造方法创建TreeSet集合对象,要求元素类实现Comparable<元素类>接口,重写compareTo方法
2. 比较器排序
使用有参构造方法创建TreeSet集合对象,将实现了Comparator接口且重写compare方法的对象当作构造方法的参数使用
红黑树左边小于根右边大于根,无论是自然排序还是比较器排序,添加元素的顺序分别由重写的compareTo方法和重写compare方法决定
*/
使用TreeSet存储自定义学生对象,按照年龄从小到大排序,且去重
- 自然排序 是通过compareTo方法进行比较的,而compareTo方法在Comparable<元素类>接口中,所以要实现Comparable<元素类>接口
第一个元素为根,从第二个元素开始用compareTo方法比较元素,返回0不添加
实现类
package com.shujia.day14;
import java.util.TreeSet;
/*
使用TreeSet存储自定义学生对象,按照年龄从小到大排序,且去重
若创建TreeSet对象是无参构造方法的话,底层创建TreeMap无参构造方法创建的,comparator = null;走的自然排序
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建TreeSet的集合对象
TreeSet<Student2> set1 = new TreeSet<>();
//创建元素对象
Student2 s1 = new Student2("魏一民", 18);
Student2 s2 = new Student2("陈真", 18);
Student2 s3 = new Student2("李建国", 16);
Student2 s4 = new Student2("魏一民", 18);
Student2 s5 = new Student2("小虎", 15);
//添加元素
set1.add(s1);
set1.add(s2);
set1.add(s3);
set1.add(s4);
set1.add(s5);
//遍历集合
for (Student2 student2 : set1) {
System.out.println(student2);
}
}
}
学生对象
package com.shujia.day14;
public class Student2 implements Comparable<Student2> {
private String name;
private int age;
public Student2() {
}
public Student2(String name, int age) {
this.name = name;
this.age = age;
}
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student2 o) {
//这个方法的返回值,决定待插入的元素的顺序,是左边还是右边还是不添加
//这里的逻辑需要我们自己编写
//显式条件:按照年龄从小到大排序
//k.compareTo(t.key)
// this -- k
// o -- t.key
int i = this.age - o.age;
//隐式条件 当年龄一样的时候,比较姓名
return (i == 0) ? this.name.compareTo(o.name) : i;
}
}
2.比较器排序
实现类
package com.shujia.day14;
import java.util.Comparator;
import java.util.TreeSet;
/*
TreeSet的比较器排序
通过观察源码发现.要想使用比较器排序,就得保证TreeMap中的comparator参数不是null,
要想保证TreeMap中的comparator参数不是null,就得使用TreeMap有参构造方法来创建,就要保证在创建TreeSet对象的时候
,传入一个实现了Comparator的对象
*/
//class ComparatorImpl implements Comparator<Student3>{
// @Override
// public int compare(Student3 o1, Student3 o2) {
// //cpr.compare(key, t.key);
// // o1 - key - 待插入的元素
// // o2 - t.key - 根的元素
// //需求:按照年龄从小到大排序,并去重
// int i = o2.getAge() - o1.getAge();
// return (i==0)?o1.getName().compareTo(o2.getName()):i;
// }
//}
public class TreeSetDemo3 {
public static void main(String[] args) {
// TreeSet<Student3> set1 = new TreeSet<>(new ComparatorImpl());
TreeSet<Student3> set1 = new TreeSet<>(new Comparator<Student3>() {
@Override
public int compare(Student3 o1, Student3 o2) {
//cpr.compare(key, t.key);
// o1 - key - 待插入的元素
// o2 - t.key - 根的元素
//需求:按照年龄从小到大排序,并去重
int i = o2.getAge() - o1.getAge();
return (i == 0) ? o1.getName().compareTo(o2.getName()) : i;
}
});
//创建元素对象
Student3 s1 = new Student3("魏一民", 18);
Student3 s2 = new Student3("陈真", 18);
Student3 s3 = new Student3("李建国", 16);
Student3 s4 = new Student3("魏一民", 18);
Student3 s5 = new Student3("小虎", 15);
//添加元素
set1.add(s1);
set1.add(s2);
set1.add(s3);
set1.add(s4);
set1.add(s5);
//遍历集合
for (Student3 student : set1) {
System.out.println(student);
}
}
}
学生对象
package com.shujia.day14;
public class Student3 {
private String name;
private int age;
public Student3() {
}
public Student3(String name, int age) {
this.name = name;
this.age = age;
}
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Treeset中的add方法源代码解析
// 结论1: TreeSet调用的add方法底层是调用了TreeMap中的put方法进行添加元素的
/*
//创建一个TreeSet对象
TreeSet<String> set1 = new TreeSet<>();
*/
class TreeSet{
private transient NavigableMap<E,Object> m; // null
private static final Object PRESENT = new Object();
public TreeSet() {
this(new TreeMap<E,Object>()); // this(...)
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
//set1.add("hello");
//set1.add("world");
public boolean add(E e) {
// E - String
// e - "world"
// PRESENT - new Object();
return m.put(e, PRESENT)==null;
}
}
class TreeMap{
private transient Entry<K,V> root; // null
public TreeMap() {
comparator = null;
}
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
public V put(K key, V value) {
// key - "world"
// value - new Object()
Entry<K,V> t = root; // 第一个元素添加的时候,树连根都没有,是null
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator; // null
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key; // Student2
do {
parent = t; // "hello"
cmp = k.compareTo(t.key); // "world".compareTo("hello")
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理