Collection集合工具类源码解读(五) --- TreeMap 和 TreeSet

本文详细解析了Java中TreeMap和TreeSet的内部结构和工作原理,包括它们的属性、构造函数以及put方法的排序逻辑。重点介绍了如何通过比较器自定义排序规则,并探讨了相关API的使用,如获取、删除和比较操作。此外,还阐述了TreeSet的构造方式及其与TreeMap的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


往期:

9、TreeMap

9.1 先看看属性

image-20220112154241822

TreeMap就是一个Hash表内存红黑树的结构

  • comparator:比较器,可以通过构造函数传入
  • root:根节点指针

9.2 构造函数

image-20220112154620198

  • TreeMap():无参构造,默认自然排序
  • TreeMap(Comparator<? super K> comparator):自定义排序方法
  • TreeMap(Map<? extends K, ? extends V> m):传入一个Map复制,但是和无参构造一样自然排序
  • TreeMap(SortedMap<K, ? extends V> m):传入一个SortedMap,使用SortedMap的比较器,同时复制其内容

9.3 put方法分析排序

写一个demo

public class TreeMapDemo {
    public static void main(String[] args) {
        TreeMap<Object, Integer> treeMap = new TreeMap<>();
        treeMap.put("c",1);
        treeMap.put("a",1);
        treeMap.put(new Person("xiaoming"),1);
        treeMap.put("b",1);
        treeMap.put(new Person("xiaohong"),1);
    }

    static class Person implements Comparable<Object>{
        String name;
        Person(String name){
            this.name = name;
        }

        @Override
        public int compareTo(Object o) {
            if (o.getClass()==String.class)
                return name.compareTo((String) o);
            else if (o.getClass()==Person.class)
                return name.compareTo(((Person) o).name);
            else return 0;
        }
        
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}

第一次put

image-20220112155907603

image-20220112160110011

  1. put方法第一次进入,必然进入第一个if,因为root为空
  2. 此时比较自己的key,这个compare方法先判断是否有比较器
    1. 用无参构造,没有比较器,默认用对应类型的compareTo方法
    2. compareTo方法需要类型实现Comparabled接口,并且重写compareTo方法才能做比较
    3. String类型默认有compareTo方法,是按字典顺序比较的,所以第一个"c"能put进去
    4. 自定义类型要实现Comparabled接口:如图,左侧不实现Comparabled接口是会抛异常的

image-20220112164024957

image-20220112162113323


以后的put

image-20220112161519962

  1. 第二次以及以后进入put就会直接到图上位置。先获得TreeMap的比较器
    1. 如果比较器不为空:用比较器比较
    2. 如果比较器为空:用compareTo方法比较
  2. 比较器或者compareTo方法都会返回一个值cmp ,根据这个判断谁大谁小
  3. 然后将其插入相关位置,或者替换之前的元素

如果用比较器怎么写?

public static void main(String[] args) {
    	//传入一个Comparator,可以采用lambda表达式
        TreeMap<Object, Integer> treeMap = new TreeMap<>((o1,o2)->{
           if (o1.getClass()==String.class&&o2.getClass()==String.class){
                return ((String) o1).compareTo((String) o2);
            }
            else if (o1.getClass()==Person.class&&o2.getClass()==Person.class){
                return  ((Person) o1).name.compareTo(((Person) o2).name);
            }
           else return 0;
        });


        treeMap.put("c",1);
        treeMap.put("a",1);
        treeMap.put(new Person("xiaoming"),1);
        treeMap.put("b",1);
        treeMap.put(new Person("xiaohong"),1);
        System.out.println(treeMap);
    }

    static class Person{
        String name;
        Person(String name){
            this.name = name;
        }
        
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
}

image-20220112164424243

将demo重写,构造器传入一个Comparator,可以采用lambda表达式,lambda表达式里返回一个最后的int值就行了

9.4 一些常用API

image-20220112170954426

image-20220112171001476

如果Comparator不为空就用比较器比较排序之后再取值,如果为空就用compareTo比较

还有一些静态的方法:

image-20220112185412958

这些静态方法为一些API提供支持:

  • firstEntry():获得第一个Entry
  • lastEntry():获得最后一个Entry
  • pollFirstEntry():删除第一个Entry
  • pollLastEntry():删除最后一个Entry
  • 严格小于
    • lowerEntry(K key):获得一个key比传入key小的Entry
    • lowerKey(K key):获得一个key比传入key小的Key
  • 严格大于
    • higherEntry(K key):获得一个key比传入key大的Entry
    • higherKey(K key):获得一个key比传入key大的Key
  • 小于等于
    • floorEntry(K key):获得一个key比传入key小,或者等于key的Entry
    • floorKey(K key):获得一个key比传入key小,或者等于key的Key
  • 大于等于
    • ceilingEntry(K key):获得一个key比传入key大,或者等于key的Entry
    • ceilingKey(K key):获得一个key比传入key大,或者等于key的Key
  • 一些其他的API
  • subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) :返回一个从fromKey到toKey的NavigableMap
  • subMap(K fromKey, K toKey) :返回一个从fromKey到toKey的SortedMap
  • headMap(K toKey, boolean fromInclusive) :返回一个Key小于(或等于,如果fromInclusive为真)toKey的NavigableMap
  • headMap(K toKey) :返回一个Key小于等于toKey的SortedMap
  • tailMap(K fromKey, boolean fromInclusive) :返回一个Key大于(或等于,如果fromInclusive为真)fromKey的NavigableMap
  • tailMap(K fromKey) :返回一个Key大于等于fromKey的SortedMap

10、TreeSet

10.1 先看看属性

image-20220112190513398

  • 一个NavigableMap,实际上,TreeMap就是实现NavigableMap接口的一个类
  • 常量PRESENT,和HashSet里的用途一样

10.2 构造函数

image-20220112190857750

image-20220112191113172

  • TreeSet():无参构造,new一个TreeMap

  • TreeSet(Comparator<? super E> comparator):有参构造,new 一个TreeMap,自定义比较器

  • TreeSet(NavigableMap<E,Object> m):有参构造,传入一个NavigableMap,将内置的NavigableMap置为该map

  • TreeSet(Collection<? extends E> c):有参构造,传入一个集合,用集合初始化内置的map

  • TreeSet(SortedSet s):有参构造,传入一个SortedSet,用SortedSet初始化内置的map

10.3 一些API

都是封装的TreeSet的API,没什么可多说的

  • first():返回集合中第一个元素

  • last():返回集合中最后一个元素

  • lower(E e):返回集合比e小的元素

  • higher(E e):返回集合比e大的元素

  • floor(E e):返回集合小于等于e的元素

  • ceiling(E e):返回集合大于等于e的元素

  • subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) :返回从from到to的NavigableSet

  • subSet(E fromElement, E toElement):返回从from到to的SortedSet

  • tailSet(E fromElement):返回大于或等于from的SortedSet

  • tailSet(E fromElement, boolean inclusive):返回大于(或等于当inclusive为true时)的NavigableSet

  • headSet(E toElement):返回小于或等于to的SortedSet

  • headSet(E toElement, boolean inclusive):返回小于(或等于当inclusive为true时)to的NavigableSet

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值