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的源码大同小异

目录
相关文章
|
4天前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
28 3
|
1天前
|
安全 Java 程序员
|
1天前
|
存储 Java C++
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列
10 0
|
2天前
|
Java
Java Class类
Java Class类
8 0
|
8天前
|
Java 编译器
Java Character 类
4月更文挑战第13天
|
9天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
13天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
13 0
|
13天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
17 0
|
13天前
|
存储 Java 编译器
Java集合丛林:深入了解集合框架的秘密
Java集合丛林:深入了解集合框架的秘密
15 0
Java集合丛林:深入了解集合框架的秘密
|
15天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
23 9