【Java 数据结构】TreeMap和TreeSet的介绍

这篇具有很好参考价值的文章主要介绍了【Java 数据结构】TreeMap和TreeSet的介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet


目录

1、认识 TreeMap 和 TreeSet

2、TreeMap 的主要成员变量

3、TreeMap 的主要构造方法

4、TreeMap 和 TreeSet 的元素必须可比较

5、TreeMap 和 TreeSet 关于 key 有序 

6、TreeMap 和 TreeSet 的关系 

7、总结


1、认识 TreeMap 和 TreeSet

TreeMap 和 TreeSet 是Java中利用搜索树实现的 Map 和 Set,它们的底层是红黑树,而红黑树是一棵近似平衡的二叉搜索树,关于红黑树相关知识后续讲解。本期主要是学会 TreeMap 和 TreeSet 的使用,以及知道他们的特点即可。

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet


2、TreeMap 的主要成员变量

// 存储传入比较器的引用
private final Comparator<? super K> comparator;

// 搜索树的根节点
private transient Entry<K,V> root;

// 节点个数
private transient int size = 0;

// 统计搜索树结构修改的次数
private transient int modCount = 0;

这里我们需要注意的是 comparator 这个引用,它是用来接收一个比较器的,主要功能后续会讲解,这里注意一下即可。


3、TreeMap 的主要构造方法

public TreeMap() {
    comparator = null;
}

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

public TreeMap(Map<? extends K, ? extends V> m) {
    comparator = null;
    putAll(m);
}
  • 第一个构造方法,没什么意外的,你没传比较器嘛,自然就是 null。
  • 第二个是传了比较器的构造方法, 指定了比较器也很简单。
  • 第三个构造方法, 则是把你传递的 Map 构造一个新的树映射,包含与给定映射相同的映射,并根据其 key 的自然顺序进行排序,这些 key,必须可相互比较!

4、TreeMap 和 TreeSet 的元素必须可比较

因为 TreeMap 和 TreeSet 实现了 SortedSet 接口,表示是一个需要实现排序功能的 Map 或 Set,那实现排序的前提,你放入的元素必须是可比较的,那么也就是说,当你往 TreeMap 里面放 key 的时候,这个 key 必须可比较,也就是重写了 compaerTo 方法,你也可也直接传一个比较器也是可以的。

public class Test {
    public static void main(String[] args) {
        Map<Person, Integer> map = new TreeMap<>();
        System.out.println(map);
    }
}

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet

这个报错就是在说, Person 无法被转换成 Comparable,也就是在 TreeMap 底层实现中无法将 key 对象中的 compareTo 方法。

具体我们还是要去看 TreeMap 的无参构造方法以及 put 的源码:

public TreeMap() {
    comparator = null;
}

对于 TreeMap 的无参构造方法,其实很简单,如果你没有传比较器进去,默认就是 null 的,接下来就得看一下 put 方法了。

源码中比较多,我们这里只截取一小部分,能明白为啥重写 compareTo 方法即可。

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet

很明显,我们是第一次 put 元素,所以搜索树的根节点也就是 root 节点为 null,接着将我们 put 进去的 key 作为 compare 两个参数传递进去,接着去看 compare 的实现:

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet这里我们没有传比较器,所以刚开始的无参构造方法已经将 comparator 置 null了,很明显这里可以发现,如果我们传了比较器,就按照比较器的方式来比较,如果没有比较器,则会将 key 转换成 Comparable<Person>,这个尖括号中的类型, 此时我们这里是转换成 Person,这也是泛型上界的相关知识,所以即最终调用了我们 key 对象中的 compareTo 方法,那如果我们没有实现 Comparable 这个接口,也没有重写 compareTo 方法自然会抛异常。

当然后续 put 元素也是按照上面的方法来比较的,有比较器,使用比较器来比较,无比较器,调用对象中的 compareTo 进行比较。


5、TreeMap 和 TreeSet 关于 key 有序 

我们前面讲到过, TreeMap 和 TreeSet 的底层其实是搜索树,而且是红黑树,那么中序遍历搜索树是有序的,也即按照 key 提供的比较方式,或者你自己提供的比较器,关于 key 是有序的。

class Person implements Comparable<Person> {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Person o) {
        return this.age - o.age;
    }
}

public class Test {
    public static void main(String[] args) {
        TreeMap<Person, Integer> map = new TreeMap<>();
        map.put(new Person("张三", 12), 1);
        map.put(new Person("李四", 21), 2);
        map.put(new Person("王五", 16), 3);
        Set<Map.Entry<Person, Integer>> entrySet = map.entrySet();
        for (Map.Entry<Person, Integer> personIntegerEntry : entrySet) {
            System.out.println(personIntegerEntry);
        }
    }
}

由于 Map 没有继承于Iterable 接口,所以不能采用 for-each 遍历,只能返回 Key-value 的映射关系放入 Set 中进行遍历。

上述代码是按照 Person 中的年龄进行比较的,所以如果最终打印出来的结果是 12 21 16 这样的年龄排序的顺序话,也足以说明,在 TreeMap 和 TreeSet 中是关于 key 有序的,打印结果:

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet

看到这,可能有的小伙伴说,确实是关于 key 有序,但是怎么保证底层是一棵搜索树呢?其实也很简单验证,搜索树前几期也讲过,如果是按照我们 Person 类比较的方式的话,那么根节点的左边都小于它,根节点的右边都大于它,这里我们通过调试看看 map 中存储的结构就ok了:

java中的treeset和treemap,Java数据结构,数据结构,TreeMap,TreeSet这里我们通过调试的方式进入到源码中,输入我们想观察的变量,于是可以看到,确实是一棵搜索树,而且不是简单的二叉搜索树,是一棵红黑树。

为什么是这里就能看出来是红黑树呢,因为如果是按照我们前面讲二叉搜索树的逻辑, 根节点一定是第一次插入的 “张三,12”,而这里跟节点为什么是 “王五,16”,因为当插入 “王五” 的时候,搜索树的左右子树高度不平衡了,红黑树进行了旋转调整,至于更多底层实现细节,目前我们可以不用关心,由此也可能看出来并不是一棵简单的二叉搜索树。


6、TreeMap 和 TreeSet 的关系 

上期其实也提到过,Set 的底层其实就是 Map,而 TreeSet 也是一样,底层仍然是 TreeMap,拿什么证明呢?其实我们来看 Set 的构造方法就可以了:

TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}

public TreeSet() {
    this(new TreeMap<E,Object>());
}

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

public TreeSet(Collection<? extends E> c) {
    this();
    addAll(c);
}

这里的 NavigableMap 也是一个继承 SortedMap 的接口,因此具有SortedMap,Map接口的属性方法,通过上述的构造方法也能看出,当你实例化一个 TreeSet 对象的时候,本质上还是 new 了一个 TreeMap 对象。而能明显看到,value 为一个 Object 默认对象。


7、总结

TreeMap 和 TreeSet 底层都是红黑树,插入删除查找的时间复杂度为 O(logN),数据关于 key 是有序的,key 必须要能够比较,不然会抛出 ClassCastException 异常,主要运用于需要 key 有序的场景下,TreeMap 和 TreeSet 是线程不安全的。 


下期预告:【Java 数据结构】HashMap和HashSet文章来源地址https://www.toymoban.com/news/detail-808213.html

到了这里,关于【Java 数据结构】TreeMap和TreeSet的介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中TreeSet的基本介绍,细节讨论,使用注意事项,常用方法,底层源码分析

    TreeSet 是 Java 中的一个有序集合实现,它基于红黑树数据结构来存储元素, 可以保持元素的自然顺序(默认情况下升序)或者根据自定义比较器来进行排序 。下面是关于 TreeSet 的基本介绍、细节讨论、使用注意事项、常用方法以及一些底层实现细节。 基本介绍: TreeSet 是

    2024年02月11日
    浏览(29)
  • Java数据结构学习和源码阅读(线性数据结构)

    链表的数据结构 一组由节点组成的数据结构,每个元素指向下一个元素,是线性序列。 最简单的链表结构: 数据 指针(存放执行下一个节点的指针) 不适合的场景: 需要循环遍历将导致时间复杂度的提升 链表分类—单向链表 链表结构: 数据 指针 Next(指向下一个节点)

    2024年02月12日
    浏览(35)
  • Java数据结构

    java数据结构有: 1、数组                                2、列表  (List) 3、集合(Set)                   4、栈 (Stack)                                   5、队列  (Queue)                6、树 (Tree)                                  7、堆 (Heap)       

    2024年02月08日
    浏览(29)
  • Java基础--数据结构

    Java工具包提供了强大的数据结构。在Java中的数据结构主要包括以下几种接口和类: 枚举(Enumeration)、位集合(BitSet)、向量(Vector)、栈(Stack)、字典(Dictionary)、哈希表(Hashtable)、属性(Properties) 以上这些类是传统遗留的,在Java2中引入了一种新的框架-集合框架

    2023年04月14日
    浏览(27)
  • 数据结构——链表(java)

    1.1 定义 链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。 如图所示: 1.2 链表分类 单向、双向;带头、不带头;循环、非循环 重点 :单向不带头非循环、双向不带头非循环(集合类底层) 如图:单项带头非循环链表结

    2024年02月09日
    浏览(32)
  • 数据结构---数组(java)

    1 、数组基础 1 用来存储一组类型相同的数据 2 在内存中,分配连续的空间,数组创建时要指定容量(大小) 3 数据类型[] 数组名 int[] arr = new int[10] int[] arr2 = {1,2,3,4} 4 索引---访问数组时通过索引进行操作 5 索引从0开始,最大为 arr.length -1 6 常见的错误: NullPointException ArrayI

    2024年01月23日
    浏览(34)
  • Java 数据结构

    Java 数据结构 Java 提供了丰富的数据结构来处理和组织数据。 Java 的 java.util 包中提供了许多这些数据结构的实现,可以根据需要选择合适的类。 以下是一些常见的 Java 数据结构: 数组(Arrays) 数组(Arrays)是一种基本的数据结构,可以存储固定大小的相同类型的元素。 i

    2024年02月22日
    浏览(26)
  • java 数据结构- 图

    表示多对多的关系时,这里我们就用到了图 图的常用概念 顶点 边 路径 无向图 有向图 带权图(边带权值的图也叫做网) 图的表示方式有两种:二维数组表示(邻接矩阵);链表表示(邻接表) 邻接矩阵 邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于n个顶点的图而

    2024年02月14日
    浏览(23)
  • Java 数据结构集合

    详细请转到@pdai的博客 1.1 数组 (Array) 数组的优点: 存取速度快 数组的缺点: 事先必须知道数组的长度 插入删除元素很慢 空间通常是有限制的 需要大块连续的内存块 插入删除元素的效率很低 源码分析: 1、底层数据结构是Object 2、构造函数包括无参构造和有参数构造,有参构

    2024年01月24日
    浏览(29)
  • Java进阶篇--数据结构

    #我的编程语言学习笔记# 目录 一.数组(Array): 1.1  特点: 1.2  基本操作: 1.3  使用数组的好处包括: 1.4  数组也有一些限制: 二.集合框架(Collections Framework): 2.1  列表(List): 2.1.1  数组列表(ArrayList): 扩展知识: 方法: ArrayList的遍历方式 ArrayList使用泛型 A

    2024年02月12日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包