美文网首页
Map集合、散列表、红黑树介绍

Map集合、散列表、红黑树介绍

作者: JunL_Dev | 来源:发表于2019-11-28 16:57 被阅读0次
    Start

    1. Map

    Map在《Core Java》中称之为-->映射
    映射的模型图是这样的:

    映射的模型图
    1.1 Map 和 Collection 的区别
    • Map 集合的特点:讲键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值

    • Map 和 Collection 集合的区别:

      1. Map 集合存储元素是成对出现的,Map 的键是唯一的,值是可以重复的
      2. Collection 集合存储元素是单独出现的,Collection 的儿子 Set 是唯一的,List 是可以重复的
    • 要点
      1. Map 集合的数据结构针对键有效,跟值无关
      2. Collction 集合的数据结构针对元素有效

    1.2 Map 的功能

    下面来看 Map 的源码:

    Map 的内部类 Entry

    简单常用的Map功能有这么一些:

        /**
         * 将指定值与此映射中的指定键关联(可选操作)。
         * 如果映射先前包含键的映射,则旧值将替换为指定值。
         * 如果键不是第一次存储,就用值把以前的值替换掉,返回以前的值
         * @param key 与指定值关联的键
         * @param value 要与指定键关联的值
         */
        V put(K key, V value);
    
    
        /**
         * 根据键删除值,并把值返回
         * @param key 要从映射中移除其映射的键
         */
        V remove(Object key);
        /**
         * 移除所有键值对元素
         */
        void clear();
    
    
        /**
         * 判断集合是否为空
         * @return <tt>true</tt> if this map contains no key-value mappings
         */
        boolean isEmpty();
        /**
         * 判断集合是否包含指定的键
         * @param key 要测试其在此map中的存在的密钥
         * @return <tt>true</tt> if this map contains a mapping for the specified key
         */
        boolean containsKey(Object key);
        /**
         * 判断集合是否包干指定的值
         * @param value 要测试其在此 Map 中存在的值
         * @return <tt>true</tt> if this map maps one or more keys to the specified value
         */
        boolean containsValue(Object value);
    
        /**
         * 根据键获取值
         * @param key 要返回其关联值的键
         * the value to which the specified key is mapped, or
         * {@code null} if this map contains no mapping for the key
         */
        V get(Object key);
        /**
         * 获取集合中所有的键的集合
         * @return a set view of the keys contained in this map
         */
        Set<K> keySet();
        /**
         * 返回的是键值对对象的集合
         *  @return a set view of the mappings contained in this map
         */
        Set<Map.Entry<K, V>> entrySet();
        /**
         * 获取集合中虽有值的集合
         * @return a collection view of the values contained in this map
         */
        Collection<V> values();
    
        /**
         * 返回集合中键值对的对数
         * @return the number of key-value mappings in this map
         */
        int size();
    

    下面用红色框框圈住的就是Map值得关注的子类:

    2. 散列表介绍

    无论是Set还是Map,我们会发现都会有对应的-->HashSet,HashMap

    首先我们也先得回顾一下数据和链表:

    • 链表和数组都可以按照人们的意愿来排列元素的次序,他们可以说是 有序 的(存储的顺序和取出的顺序是一致的)

    • 但同时,这会带来缺点:想要获取某个元素,就要访问所有的元素,直到找到为止。

    • 这会让我们消耗很多的时间在里边,遍历访问元素~
      而还有另外的一些存储结构:不在意元素的顺序,能够快速的查找元素的数据

    • 其中就有一种非常常见的:散列表

    2.1散列表工作原理

    散列表为每个对象计算出一个整数,称为散列码。根据这些计算出来的整数(散列码)保存在对应的位置上!

    在Java中,散列表用的是链表数组实现的,每个列表称之为桶。

    一个桶上可能会遇到被占用的情况(hashCode 散列码相同,就存储在同一个位置上),这种情况是无法避免的,这种现象称之为:散列冲突

    • 此时需要用该对象与桶上的对象进行比较,看看该对象是否存在桶子上了,如果存在,就不添加了,如果不存在则添加到桶子上
    • 当然了,如果 hashcode 函数设计得足够好,桶的数目也足够,这种比较是很少的
    • 在 JDK1.8 中,桶满时会从链表变成平衡二叉树

    如果散列表太满,是需要对散列表再散列,创建一个桶数更多的散列表,并将原有的元素插入到新表中,丢弃原来的表

    • 装填因子(load factor)决定了何时对散列表再散列~
    • 装填因子默认为 0.75,如果表中超过了 75% 的位置已经填入了元素,那么这个表就会用双倍的桶数自动进行再散列

    当然了, 在后面阅读源码的时候会继续说明的,现在简单了解一下即可
    扩展阅读:

    3. 红黑树介绍

    上面散列表中已经提过了:如果桶数满的时候,JDK8 是将链表转成红黑树的。并且,我们的 TreeSet、TreeMap 底层都是红黑树来实现的。

    各种常见的树的用途:


    来源 :https://www.zhihu.com/question/30527705/answer/52527887
    3.1二叉查找树

    二叉查找树也有个例(最坏)的情况(线性):


    上面符合二叉树的特性,但是它是线性的,完全没树的用处~

    树是要 “均衡” 才能将它的优点展示出来的,比如下面这种:

    因此,就有了平衡树这么一个概念~红黑树就是一种平衡树,它可以保证二叉树基本符合矮矮胖胖(均衡)的结构

    3.2 知新 2 - 3 树

    讲到了平衡树就不得不说最基础的2-3树,2-3树长的是这个样子:

    在二叉查找树上,我们插入节点的过程是这样的:小于节点值往右继续与左子节点比,大于则继续与右子节点比,直到某节点左或右子节点为空,把值插入进去。这样无法避免偏向问题

    而2-3树不一样:它插入的时候可以保持树的平衡!

    在2-3树插入的时可以简单总结为两个操作:

    • 合并2-节点为3-节点,扩充将3-节点扩充为一个4-节点
    • 分解4-节点为3-节点,节点3-节点为2-节点
    3.3 从 2 - 3 树到红黑树

    由于2-3树为了保持平衡性,在维护的时候是需要大量的节点交换的!这些变换在实际代码中是很复杂的,大佬们在2-3树的理论基础上发明了红黑树(2-3-4树也是同样的道理)

    • 红黑树是对2-3查找树的改进,它能用一种统一的方式完成所有变换
    • 红黑树是一种平衡二叉树,因此它没有3-节点

    红黑树就字面上的意思,有红色的节点,有黑色的节点:


    我们可以将红色节点的左链接画平看看:

    一颗典型的二叉树:


    二叉树

    将红色节点的左链接画平之后:得到2-3平衡树:


    3.4 红黑树基础知识

    前面已经说了,红黑树是在2-3的基础上实现的一种树,它能够用统一的方式完成所有变换。很好理解:红黑树也是平衡树的一种,在插入元素的时候它也得保持树的平衡,那红黑树是以什么的方式来保持树的平衡的呢?

    红黑树用的是也是两种方式来替代2-3树不断的节点交换操作:

    • 旋转:顺时针旋转和逆时针旋转
    • 反色:交换红黑的颜色
    • 这个两个实现比2-3树交换的节点(合并,分解)要方便一些

    红黑树为了保持平衡,还有制定一些约束,遵守这些约束的才能叫做红黑树:

    1. 红黑树是二叉搜索树。
    2. 根节点是黑色。
    3. 每个叶子节点都是黑色的空节点(NIL节点)。
    4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
    5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点(每一条树链上的黑色节点数量(称之为“黑高”)必须相等)。
    3.5 红黑树总结:

    红黑树可以说是十分复杂的,我在学习的时候并没有去认真细看当中的处理细节,只是大概的过了一遍,知道了整体~

    有了前辈很多优质的资料,相信要等到想要理解其中的细节,花点力气和时间还是可以掌握一二的。

    本文参考 https://mp.weixin.qq.com/s/Mi7MIjLInAxrBQRyHUVfeA
    开始和结束的图片来源网络,侵删

    End

    相关文章

      网友评论

          本文标题:Map集合、散列表、红黑树介绍

          本文链接:https://www.haomeiwen.com/subject/gqxrictx.html