java集合类史上最细讲解 - TreeSet,TreeMap篇

简介: 1.TreeSet概述TreeSet实现了Set接口,与HashSet不同的时,他是有序集合,底层是一个TreeMap默认按照升序排列,代码示例:


1.TreeSet概述


TreeSet实现了Set接口,与HashSet不同的时,他是有序集合,底层是一个TreeMap默认按照升序排列,代码示例:


TreeSet treeSet = new TreeSet();
treeSet.add("tom");
treeSet.add("lili");
treeSet.add("kangkang");
treeSet.add("abc");
System.out.println(treeSet);  // [abc, kangkang, lili, tom]


2.自定义排序规则


TreeSet可以在初始化对象的时候传入一个接口对象,并对属性进行赋值


public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
---
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}


我们可以通过内部类的形式传入一个比较器,借助字符串的compareTo方法对TreeSet的排序进行自定义例如,如下是一个升序排序:


TreeSet treeSet = new TreeSet(new Comparator() {
    @Override
    public int compare(Object o1, Object o2) {
        return ((String) o1).compareTo((String) o2);
    }
});
treeSet.add("tom");
treeSet.add("lili");
treeSet.add("kangkang");
treeSet.add("abc");
System.out.println(treeSet);


现在,更改一下o1和o2的位置,排序变成了逆序排序:


TreeSet treeSet = new TreeSet(new Comparator() {
    @Override
    public int compare(Object o1, Object o2) {
        return ((String) o2).compareTo((String) o1);
    }
});
treeSet.add("tom");
treeSet.add("lili");
treeSet.add("kangkang");
treeSet.add("abc");
System.out.println(treeSet);


3.添加元素排序机制源码解读


方法:addTreeSet首先会进入


public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}


方法:putTreeMap之后,进入


public V put(K key, V value) {
    return put(key, value, true);
}


继续步入,直到添加了第二个元素,再次进入接受比较器的代码(核心):🍳


Comparator<? super K> cpr = comparator;
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 {
            V oldValue = t.value;
            if (replaceOld || oldValue == null) {
                t.value = value;
            }
            return oldValue;
        }
    } while (t != null);
}


接下来我们来解析一下上面这段代码:接收了传入的比较器:


Comparator<? super K> cpr = comparator;


执行:if不为空,会进入cpr此时的进行比较器的比较🐱‍💻t.keykey方法,随后传入两个元素compare,会动态绑定到我们传入的匿名内部类的cpr.compare执行


cmp = cpr.compare(key, t.key);


4.发散思维


注意:当我们传入比较器到TreeSet中时,如果TreeSet判断存在两个元素是相等的,则不会进行添加操作,怎么才算元素相等,取决于我们传入的比较器👨🏻

例如:我们想实现一个功能,根据元素字符串的长度进行升序排序,那么我们可以这样编写比较器:


TreeSet treeSet1 = new TreeSet(new Comparator() {
    @Override
    public int compare(Object o1, Object o2) {
        return ((String) o1).length() - ((String) o2).length();
    }
});


那么此时,元素的长度将会变成元素相等的条件,故我们执行如下代码块:


treeSet1.add("tom");
treeSet1.add("lili");
treeSet1.add("wangwei");
treeSet1.add("wu");
treeSet1.add("zhan");
System.out.println(treeSet1);  // [wu, tom, lili, wangwei]


会发现,“zhan”元素并没有添加成功!🍤

注意:对于TreeMap的此种情况,他的Key值依然不会添加成功,但是会替换value的值


5.TreeMap


TreeMapTreeSet差距不大,TreeMap保存键值对,默认按照键值升序排序


TreeMap treeMap = new TreeMap();
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("smith","史密斯");
System.out.println(treeMap);  // {jack=杰克, smith=史密斯, tom=汤姆}


6.TreeMap的自定义排序


和TreeSet一样,TreeMap也可以传入你个匿名内部类,实现自定义排序的效果

例如:按照Key值升序排序:


TreeMap treeMap = new TreeMap(new Comparator() {
    @Override
    public int compare(Object o, Object t1) {
        return ((String) o).compareTo((String) t1);
    }
});
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("smith","史密斯");
System.out.println(treeMap);


按照Key值逆序排序:


TreeMap treeMap = new TreeMap(new Comparator() {
    @Override
    public int compare(Object o, Object t1) {
        return ((String) t1).compareTo((String) o);
    }
});
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("smith","史密斯");
System.out.println(treeMap);


按照字符串长度从小到大排序:


TreeMap treeMap = new TreeMap(new Comparator() {
    @Override
    public int compare(Object o, Object t1) {
        return ((String) o).length() - ((String) t1).length();
    }
});
treeMap.put("jack","杰克");
treeMap.put("tom","汤姆");
treeMap.put("smith","史密斯");
System.out.println(treeMap);


TreeMapTreeSet的源码大同小异

目录
相关文章
|
11天前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
27 1
|
10天前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
24 0
java基础(13)String类
|
4天前
|
Java API
Java的日期类都是怎么用的
【10月更文挑战第1天】本文介绍了 Java 中处理日期和时间的三个主要类:`java.util.Date`、`java.util.Calendar` 和 `java.time` 包下的新 API。`Date` 类用于表示精确到毫秒的瞬间,可通过时间戳创建或获取当前日期;`Calendar` 抽象类提供丰富的日期操作方法,如获取年月日及时区转换;`java.time` 包中的 `LocalDate`、`LocalTime`、`LocalDateTime` 和 `ZonedDateTime` 等类则提供了更为现代和灵活的日期时间处理方式,支持时区和复杂的时间计算。
26 14
|
8天前
|
安全 Java 编译器
java访问类字段
java访问类字段
|
10天前
|
Java
java的class类
java的class类
18 5
|
10天前
|
存储 安全 Java
Java 常用集合分类
Java 常用集合分类
13 2
|
11天前
|
Java 数据处理
Java Scanner 类详解
`Scanner` 类是 Java 中 `java.util` 包提供的强大工具,用于从多种输入源(如键盘、文件、字符串)读取数据。本文详细介绍如何创建 `Scanner` 对象并使用其常用方法(如 `next()`, `nextInt()`, `nextLine()` 等)。通过示例代码展示如何从标准输入、字符串及文件中读取数据,并进行输入验证。使用时需注意关闭 `Scanner` 以释放资源,并确保输入类型匹配,避免异常。掌握 `Scanner` 可显著提升程序的数据处理能力。
|
5月前
|
存储 安全 Java
java集合框架及其特点(List、Set、Queue、Map)
java集合框架及其特点(List、Set、Queue、Map)
|
2月前
|
存储 安全 Java
【Java集合类面试二十五】、有哪些线程安全的List?
线程安全的List包括Vector、Collections.SynchronizedList和CopyOnWriteArrayList,其中CopyOnWriteArrayList通过复制底层数组实现写操作,提供了最优的线程安全性能。
|
2月前
|
Java
【Java集合类面试二十三】、List和Set有什么区别?
List和Set的主要区别在于List是一个有序且允许元素重复的集合,而Set是一个无序且元素不重复的集合。
下一篇
无影云桌面