`
后来我们都老了
  • 浏览: 34634 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Map原理及使用

阅读更多

Hashmap

原理

hashmap的底层数据结构散列表,即:数组+链表,创建的时候初始化一个数组,每个节点可以为一个链表


 当一键值对发生put操作时,

首先根据key的hash值得到这个元素在数组中的位置(即下标),如果这个位置上已经存在其他元素,将进行下一步操作。

 

  1. 由于同一点是链表方式存储,会将原来的元素向后推
  2. 然后新的元素放在这个位置上

put操作可能会出现冲突,冲突分两种:

 

  1. 不同的key值,通过hash函数得出相同的index,这种冲突通过上面所说的链表方式存储。
  2. 相同的key值,直接覆盖。

所以为了减少冲突,尽量将hashmap 的长度设置为2的次方,因为如果不是2的次方,经过hash & 操作,最后一位总是0如下图,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能存放元素了,空间浪费相当大,而且这样可以使用的位置比数组长度小了很多,增加了冲突的几率,故减慢的查询的效率(如果每一个节点都不存在链表,则不需要循环,查询效率会高,所以尽量均匀分布)。

 

同理,当一键值对发生get操作时,会经过hash函数计算得到index,如果节点为链表有多个元素,则迭代用key.equals()比较获取。


 

容量

源码多了恶心,少量如下:

 

static final int DEFAULT_INITIAL_CAPACITY = 16;
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;

 三个常量中可以看出,默认的容器大小是16,最大长度是2的30次方,load factor默认是0.75,扩充的临界值是16*0.75=12,

 

如果put操作检测出hashmap的容量不足,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元个数能够有效的提高hashmap的性能。

实战总结

所以如果我们想初始化一个容量大小为13的容量,合理的方式是什么呢?

1.Map<String, String> map1 = new HashMap<>(13);
2.Map<String, String> map2 = new HashMap<>(13, 1);
3.Map<String, String> map3 = Maps.newHashMapWithExpectedSize(13);

以上是三种初始化方式

第一种

直接根据构造方法初始化,那么map会初始化一个容量大小为16的map,在超过16*0.75即12的时候发生扩容,这显然不是我们想看到的。

第二种

在构造容量为13的基础上,将负载因子的值设为1,那么map将会在超过16个元素后开发扩容,可以满足我们的预期效果,但这种情况一旦发生扩容,随着元素的增多,碰撞的几率就会升高,链表就会很长,这样就大大的降低了性能。

第三种

使用guava的方式初始化一个map,根据源码发现guava已经帮我算好了,真正需要扩容的临界点,

可以满足我们的期望,同时也不需要修改负载因子的值,所以无特殊情况下,建议使用此方式。

LinkedHashMap

其底层实现基本与hashmap一致,但是linkedHashMap多维护了一张双向的链表



 LinkedHashMap成员变量

增加accessOrder属性,默认为false,当为false时,按插入顺序排序,当为true时,

按LRU+插入顺序排序

LRU:最近最少使用算法


Entry

 

其保存的Entry对象增加了两个属性,before和after



 存数据

 

LinkedHashMap没有重写put方法,而是重写了addEntry()方法,把新的Entry也加到header

 

链表结构里面去



 

 

取数据

 

1、先调用hashmap的getEntry()方法获取Entry



 当accessOrder为true时,把最近使用的当前Entry移到header的before位置,而LinkedHashIterator遍历的方式是从header.after开始遍历,先得到最近使用的Entry

 

最近使用:accessOrder为true时,get(Object key)方法会导致Entry最近使用put(K key, V value)/putForNullKey(value)只有是覆盖操作时会导致Entry最近使用。它们都会触发recordAccess方法从而导致Entry最近使用



 

 删除

 

LinkedHashMap没有重写remove(Object key)方法,重写了被remove调用的recordRemoval方法,删除了双向链表中的before和after。

HahsMap remove(Object key)把数据从横向数组 * 竖向next链表里面移除之后(就已经完成工作了,所以HashMap里面recordRemoval是空的实现调用了此方法



 LinkedHashMap的遍历


 总结

 

1、什么是LRU+插入顺序?

put(K key, V value)/putForNullKey(value)只有是覆盖操作时会导致Entry最近使用,即为插入顺序;accessOrder为true时,get(Object key)方法会导致Entry最近使用,即为LRU

2、LinkedHashMap和HashMap的区别

  • LinkedHashMap继承HashMap,结构2里数据结构的变化交给HashMap就行了。
  • 结构1里数据结构的变化就由LinkedHashMap里重写的方法去实现。
  • 简言之:LinkedHashMap比HashMap多维护了一个链表。

 

 

  • 大小: 493.1 KB
  • 大小: 341.4 KB
  • 大小: 45.2 KB
  • 大小: 111.2 KB
  • 大小: 59.3 KB
  • 大小: 156.9 KB
  • 大小: 174.6 KB
  • 大小: 66.8 KB
  • 大小: 168.4 KB
  • 大小: 117.2 KB
  • 大小: 118.6 KB
0
0
分享到:
评论

相关推荐

    map总结,原理,使用

    ### Map 总结:原理与使用详解 #### 一、Map 概述 **Map** 是 C++ STL(Standard Template Library)中的一种关联容器,它主要用于存储...通过理解其原理及使用方法,可以在实际开发中更高效地运用这一强大的工具。

    Map-Reduce原理体系架构和工作机制,eclipse与Hadoop集群连接

    - 使用Eclipse创建新的Map-Reduce项目。 - 编写Map和Reduce函数。 - 配置作业参数,如输入输出路径等。 **4. 提交和运行作业** - 将编写的Map-Reduce应用程序提交到Hadoop集群。 - 监控作业的执行进度和状态。 ##...

    素材_tilemap素材_使用TileMap快速构造2D关卡_

    2. TileMap的工作原理: TileMap通常由一个二维数组表示,每个元素对应一个瓷砖ID。这些ID与预设的瓷砖图像库相联系,使得开发者可以通过简单的数据操作就能改变关卡布局。在Unity、Cocos2d-x等引擎中,都有内置的...

    depthmap10 软件使用教程

    ### Depthmap10软件使用教程知识点汇总 #### 一、深度了解Depthmap10 - **简介** - **发布日期与版本**:2010年9月发布的Depthmap10版本为10.08.00r。 - **作者**:Joao Pinelo 和 Alasdair Turner。 - **目的**...

    mAP实现原理及计算方式讲解.txt

    mAP实现原理及计算方式讲解.txt

    END_MESSAGE_MAP宏的内部实现原理

    ### END_MESSAGE_MAP宏的内部实现原理深度解析 在深入探讨`END_MESSAGE_MAP`宏的内部实现之前,我们首先需要理解MFC(Microsoft Foundation Classes)框架如何处理Windows消息。MFC框架设计了一套高效的机制来映射...

    纠错码中turbo码的译码原理 MAP算法

    Turbo码是一种高效的纠错编码...总之,Turbo码的MAP译码原理是现代通信系统中纠错编码的重要组成部分,它通过迭代和软信息交换实现了高错误纠正能力。理解并掌握这一技术对于设计高效、可靠的通信系统具有重要意义。

    UnityShader 浮雕凹凸贴图BumpMap与法线贴图NormalMap的原理及其区别

    这两种贴图方法都用于模拟物体表面的微小不平,从而在视觉上增加深度和复杂性,但它们的工作原理和应用方式有所不同。 首先,让我们了解浮雕凹凸贴图(BumpMap)。BumpMap是一种灰度图像,其中的每个像素值代表对应...

    cognos map控件的使用

    将创建的数据表打包成Cognos包,并命名为“cognos map”,以便在Report Studio中使用。 #### Step 3: 运行 Report Studio 选择已发布的包,导入所需的数据源。 #### Step 4: 添加数据元素 在Report Studio中,从...

    Map (c++实现的简易map)

    自定义`Map`的主要目的是为了学习和理解数据结构的工作原理,以及如何在C++中实现这些数据结构。尽管`std::map`已经提供了一套完整的功能,但自己动手实现可以帮助开发者深入理解底层的红黑树(Red-Black Tree)或...

    map.zip_电机_电机MAP_电机效率_电机效率map_绘制电机MAP

    总的来说,电机效率MAP的绘制是一个结合了物理原理、数据处理和可视化技术的过程,对于理解和优化电机性能具有深远的影响。"map.zip"提供的工具或许能简化这一过程,使得非专业用户也能方便地分析电机的效率特性。

    MybatisPlus多数据源原理及使用注意点.pdf

    MybatisPlus多数据源原理及使用注意点 MybatisPlus多数据源原理及使用注意点.pdf 文件提供了关于MybatisPlus多数据源的详细信息,包括原理、配置方式、使用注意点等内容。下面是根据文件内容生成的相关知识点: 一...

    map_电机_效率map_

    在实际使用"map.m"这个工具时,用户可能需要输入电机的电气和机械参数,如额定功率、电压、电流、转速等,并指定一系列工作点进行计算。然后,程序会自动生成对应的效率Map图形,便于用户直观地理解和分析电机的性能...

    map的用法的源代码资源

    本文将深入探讨 `map` 的用法,包括它的定义、工作原理以及在不同编程语言中的应用。 `map` 函数的初衷是将一个函数应用到一个集合(如列表、数组或元组)的所有元素上,然后返回一个新的集合,其中包含了原集合...

    STL测试程序map的使用方法

    STL(Standard Template Library,标准模板库)是C++编程语言中的一个重要组成部分,它提供了一系列高效、可重用的数据结构和算法。...通过分析提供的源代码,你可以深入理解STL map的工作原理和在实际编程中的应用。

    地图的简单使用(Map)

    了解其工作原理和使用技巧对于编写高效代码至关重要。在实际项目中,根据需求选择合适类型的Map,例如需要保持插入顺序时可以选择LinkedHashMap,需要排序则选择TreeMap,追求效率则优先考虑HashMap。

    MapStruct 1.2.0 参考指南

    #### MapStruct的工作原理: MapStruct基于Java的注释处理器API(JSR269),它可以集成到大多数常用的Java构建工具中(如Maven, Gradle等),并且也可以在集成开发环境(IDE)中使用,例如IntelliJ IDEA和Eclipse。...

    Map里面containsKey的用法

    在Java编程语言中,`Map`接口是集合框架的重要组成部分,它存储键值对,其中每个键都是唯一的。`containsKey()`方法是`Map`接口中的一个关键方法,用于检查给定的键是否存在于该映射中。在这个场景中,我们将深入...

Global site tag (gtag.js) - Google Analytics