【JavaSE】TreeSet与TreeMap源码解读

发布于:2023-01-17 ⋅ 阅读:(376) ⋅ 点赞:(0)

💁 个人主页:黄小黄的博客主页
❤️ 支持我:👍 点赞 🌷 收藏 🤘关注
🎏 格言:All miracles start from sometime somewhere, make it right now.
本文来自专栏:JavaSE从入门到精通
在这里插入图片描述


1 TreeSet

1.1 TreeSet快速入门

 相较于HashSet,TreeSet最大的特点是实现了排序,但是需要注意的是,当我们使用无参构造器创建TreeSet时,仍然是无序的。如果希望添加的元素按照字符串大小来排序则需要使用比较器Comparator,并指定排序规则。
来看下面的例子,可以看出,结果按照字符串大小进行了排序:

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String) o2);
            }
        });
        // 添加数据
        treeSet.add("lucy");
        treeSet.add("drunk");
        treeSet.add("youth");
        treeSet.add("bob");
        treeSet.add("a");

        System.out.println("treeSet = " + treeSet);
    }
}

在这里插入图片描述

1.2 TreeSet比较机制源码解读

1️⃣ 构造器把传入的比较器对象,赋给了 TreeSet 底层的 TreeMap 属性。
在这里插入图片描述
在这里插入图片描述

2️⃣ 在调用 treeSet.add(“drunk”),底层会执行到下述代码,其中cpr 就是我们的匿名内部类(对象),会动态绑定到匿名内部类的compare方法。

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  // 如果相等,即返回0,这个key就没有加入
                    return t.setValue(value);
            } while (t != null);
        }

需要注意的是,当比较结果是相等时,不会将key添加进去!

我们来看下面的例子,尝试将比较规则更改为按照字符串长度排序:

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o2).length() -((String)o1).length();
            }
        });
        // 添加数据
        treeSet.add("Drunk");
        treeSet.add("Youth");

        System.out.println("treeSet = " + treeSet);
    }
}

在这里插入图片描述
由于 Drunk 与 Youth 长度相同,因此,在底层调用比较器的时候,不加入 Youth 这一 key 值。 这也是小白时期常常容易犯的错误,导致了数据的丢失!


2 TreeMap

2.1 TreeMap快速入门

当使用无参构造器的时候,TreeMap默认按照key值进行自然排序。

import java.util.TreeMap;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        // 添加数据
        treeMap.put("drunk", "路宝");
        treeMap.put("abc", "香克斯");
        treeMap.put("cat", "多弗朗明哥");

        System.out.println("treeMap = " + treeMap);
    }
}

在这里插入图片描述

也可以传入比较器,进行自定义排序。比如,尝试按照key的字符串长度的大小进行排序:

import java.util.Comparator;
import java.util.TreeMap;

/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class TreeMapTest {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });
        // 添加数据
        treeMap.put("drunk", "路宝");
        treeMap.put("abc", "香克斯");
        treeMap.put("cat", "多弗朗明哥");
        System.out.println("treeMap = " + treeMap);
    }
}

此时,由于 cat 和 abc 两个键的长度相同,因此,后面的 cat键没有成功加入,只是将 cat 对应的值 与 abc 对应的值进行了替换!

在这里插入图片描述

2.2 TreeMap比较机制源码解读

1️⃣ 调用构造器的时候,把传入的实现了 Comparator接口的匿名内部类(对象),赋给了 TreeMap 的属性 comparator;
在这里插入图片描述

2️⃣ 在执行第一个put时,加入了一个结点作为root根节点,把 k-v 封装到 Entry对象,放入root;
在这里插入图片描述

3️⃣ 之后调用 put 方法,会调用比较器。进行所有 key 的遍历,并动态绑定到匿名内部类的compare()方法。如果发现比当前结点小,则挂到左子树,大了就挂到右子树。如果相等,则只进行value的替换,key不会加入。 使用setValue方法进行。

		int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        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
                    return t.setValue(value);
            } while (t != null);
        }

写在最后

🌟以上便是本文的全部内容啦,后续内容将会持续免费更新,如果文章对你有所帮助,麻烦动动小手点个赞 + 关注,非常感谢 ❤️ ❤️ ❤️ !
如果有问题,欢迎私信或者评论区!
在这里插入图片描述

共勉:“你间歇性的努力和蒙混过日子,都是对之前努力的清零。”
在这里插入图片描述

本文含有隐藏内容,请 开通VIP 后查看