Java_TreeSet与TreeMap源码解读

TreeSet底层是TreeMap,二者区别在于:

java 复制代码
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

TreeSet在使用方法时,e作为元素添加,而PRESENT作为一个用于占位的空对象,表示没有意义

TreeMap使用方法时,由于是作为键值对添加进去的,此时e 就等于key,而PRESENT 就等于value

TreeSet演示:

java 复制代码
package com.CollectionStu_.Set_;

import java.util.Comparator;
import java.util.TreeSet;
@SuppressWarnings({"all"})
public class TreeSet_ {
    public static void main(String[] args) {
//        TreeSet treeSet = new TreeSet();
        //1.当我们使用无参构造器创建TreeSet时,仍然是无序的
        //2.可以使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
        //  并指定排序规则
        //例:希望添加的元素能够按照字符串大小进行排序(这里是从小到大)
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //下面调用String的 compareTo方法进行字符串大小比较
                return ((String)o2).compareTo((String) o1);//从大到小把o2 和o1 对调即可
            }
        });

        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("nihao");
        treeSet.add("mary");

        System.out.println(treeSet);
        //排序前(直接输出):[jack, mary, nihao, tom]
        //排序后(从小到大):[tom, nihao, mary, jack]

        //源码分析:
        /*
        构造器:
        public TreeSet(Comparator<? super E> comparator) {
            this(new TreeMap<>(comparator));
        }
        构造器会把传入的匿名对象new Comparator() 赋给TreeSet底层的TreeMap的属性this.comparator

        在调用add("tom") 时,在底层会执行到
        Comparator<? super K> cpr = comparator; //cpr就是匿名内部类(对象)
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);  //动态绑定到匿名内部类的compare()
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else                            //如果相等,即返回0,这个数据(Key)就没有加入
                    return t.setValue(value);
            } while (t != null);
        }
         */
    }
}

TreeMap演示:

java 复制代码
package com.MapStu_.Map_;

import java.util.Comparator;
import java.util.TreeMap;
@SuppressWarnings({"all"})
public class TreeMap_ {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("jack","杰克");
        treeMap.put("tom","汤姆");
        treeMap.put("nihao","泥嚎");
        treeMap.put("smith","史密斯");
        //使用默认构造器创建TreeMap(无序的,也没有排序)
        System.out.println(treeMap);//{jack=杰克, nihao=泥嚎, smith=史密斯, tom=汤姆}

        //使用带comparator的构造器控制排序
        //    public TreeMap(Comparator<? super K> comparator) {
        //        this.comparator = comparator;
        //    }
        //例:要求按照传入的key(String) 大小进行排序
        TreeMap treeMap1 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String)o2);
            }
        });
        treeMap1.put("jack","杰克");
        treeMap1.put("tom","汤姆");
        treeMap1.put("nihao","泥嚎");
        treeMap1.put("smith","史密斯");
        System.out.println(treeMap1);

        //要求按照字符串长度大小排序
        TreeMap treeMap2 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });

            /*

            源码解读:
            1. 构造器. 把传入的实现了 Comparator接口的匿名内部类(对象),传给给TreeMap的comparator
             public TreeMap(Comparator<? super K> comparator) {
                this.comparator = comparator;
            }
            2. 调用put方法
            2.1 第一次添加, 把k-v 封装到 Entry对象,放入root
            Entry<K,V> t = root;
            if (t == null) {
                compare(key, key); // type (and possibly null) check

                root = new Entry<>(key, value, null);
                size = 1;
                modCount++;
                return null;
            }
            2.2 以后添加
            Comparator<? super K> cpr = comparator;
            if (cpr != null) {
                do { //遍历所有的key , 给当前key找到适当位置
                    parent = t;
                    cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类的compare
                    if (cmp < 0)
                        t = t.left;
                    else if (cmp > 0)
                        t = t.right;
                    else  //如果遍历过程中,发现准备添加Key 和当前已有的Key 相等,就不添加
                        return t.setValue(value);
                } while (t != null);
            }
         */
    }
}
相关推荐
wuyk5551 分钟前
18.Kruskal 算法:用最短的边连成一张网
开发语言·算法·图论
Evand J1 分钟前
【MATLAB例程,图像降噪7】高斯加权滑动窗口滤波,用于图像降噪,带质量评价,附代码下载链接
开发语言·图像处理·matlab·滑动窗口·滤波·降噪·图像滤波
还是奇怪3 分钟前
OpenAI GPT-5.6 构建指南拆解:创业公司如何用模型选择与 Responses API 降低 Agent 成本
java·数据库·人工智能·gpt
可涵不会debug4 分钟前
LangChain 文本分割器详解:字符分割、Token 分割、硬约束递归分割实战
java·前端·数据库
sbjdhjd8 分钟前
ThinkPHP 5.0.10 缓存写入型 RCE 复盘:从手动搭建、换行绕过到源码单步验证 | 05
java·后端·安全·spring·网络安全·数据挖掘·php
十年一梦惊觉醒11 分钟前
快手视频发布助手,全自动视频发布带货工具
开发语言·前端·javascript
Java后端的Ai之路11 分钟前
一文搞懂 GitHub Actions-CICD
开发语言·大模型·github·cicd·action
码匠许师傅14 分钟前
【C++三方组件】开篇总论:为什么需要以及如何选型?
开发语言·c++
程序员清风25 分钟前
记忆系统设计:让 Agent 拥有短期记忆与长期记忆
java·服务器·网络
cvby29 分钟前
C++11--右值引用和移动语义
开发语言·c++