Map,百度翻译给我的解释是映射,在Java编程中,它是存储键值对(key-value)的一种容器,也是Java程序员常用的对象。这篇博客介绍下HashMap的实现;java是面向对象编程语言,jdk为java提供了丰富的API,自然而然,在java中,数据的展示形式也是多种多样的。但是在底层语言,数据的展示就不同了,一般只有两种形式,元素值(基本类型)、数组,其他的数据类型都是这两个元素的封装,今天要说的HashMap就是如此。

  HashMap通过数组对数据进行存储的(Entry[] table)。其中,数组元素对象Entry是HashMap中的一个内部类,这个内部类记录了两个关键的东西,一个是键值对;一个next,下一个Entry。下面我介绍下将一个键值对put到HashMap中的过程;将key,value put到HashMap中,

1、拿到当前这个key的hashcode,对hashcode进行空间稀疏处理,最后得到的还是一个码,这个码在同一个字节位置的不同的整数倍上是不同的;

2、拿到上一步获得的hashcode,与当前表的长度进行与计算(h & (length-1)),获取当前key在当前数组中的坐标;

3、拿到上一步中与运算获得的坐标,在表中以阈值为单位长度,相同的位置进行查找,寻找是否存在相同的key,如果存在相同的key,那么就将key进行值替换,如果没有找到key,那么进行添加;

  for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

在这里说一下HashMap是如何进行相同的Key的查找的。在jdk中,给对象都赋予了一个身份标识,hashcode,在java中,因为一个对象在不同的特征形态下是允许有不同的hashcode的,所以,进行了第一步处理,使得一个对象只有一个hashcode;而Hashmap存储数据是通过数组,所以找制定的键值对,实际上就是找我要的key所在的键值对的位置;为此,hashmap在存储键值对时候,存储位置是根据key的hashcode和当前hashmap内存储数组的长度来进行转换而得到的(position = hashcode & (length - 1))。举个例子,实例化一个HashMap的时候,会声明存储数组table的初始化大小为16;而我要存储一个数键值对{0:"0"},那么我存储的这个键值对的位置就 0.hashcode() & (16 -1) =0;这个键值对就是存储在Hashmap中的table数组中的第一个元素;现在我再想hashmap中put进去一个元素{5:“5”},此时5.hashcode() & (16 - 1)=5,那么,我put的key为5的这个键值对存储在hashmap中的数组table中的位置就是5;然后我在想hashmap中put进去一个元素{16:16},那么我再去数组中,发现得到位置是0,但是当前这个数组,0这个位置上已经存在数了,而且还没有找到我要存的key,那么,再往这个对象中塞键值对,就用到上面我已经介绍过的Entry对象的属性,next了。

 /**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}

  上面的添加的代码,就是如果table的当前这个位置已经有元素了,这时候,你还再往这个位置上添加新元素时,这个新元素就会放到新的元素放在数组中,把之前这个位置已经存在的元素放在当前这个新元素的next上,如果后面再有新元素新增进来,这次的元素就会到后台,作为更新元素的next,那个更新的元素存储到数组table中,这样在第一段代码找可以的时候循环时,就不用挨个遍历数组元素了,只需要遍历阈值相关的制定倍数的数据,效率就高了很多,后面的get方法,用到的额也是这里put元素时的找数的方法。

这篇博客主要就是介绍Hashmap的算法,其他的细节的实现建议去看JDK源码;

HashMap 取数算法的更多相关文章

  1. codevs 1907 方格取数 3

    Description 在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. Input 第 ...

  2. 【wikioi】1907 方格取数3(最大流+最大权闭合子图)

    http://www.wikioi.com/problem/1907/ 这题我一开始想到的是状压,看到n<=30果断放弃. 然后也想到了黑白染色,然后脑残了,没想到怎么连边. 很简单的一题 黑白 ...

  3. 【网络流24题】No.9 方格取数问题 (二分图点权最大独立集)

    [题意] 在一个有 m*n 个方格的棋盘中, 每个方格中有一个正整数. 现要从方格中取数, 使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入文件示例inp ...

  4. 洛谷 P2774 方格取数问题 解题报告

    P2774 方格取数问题 题目背景 none! 题目描述 在一个有 \(m*n\) 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大. ...

  5. LibreOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

    #6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  6. 【刷题】LOJ 6007 「网络流 24 题」方格取数

    题目描述 在一个有 \(m \times n\) 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 \(2\) 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数 ...

  7. Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流)

    Libre 6007 「网络流 24 题」方格取数 / Luogu 2774 方格取数问题 (网络流,最大流) Description 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从 ...

  8. P2774 方格取数问题

    题目背景 none! 题目描述 在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.对于 ...

  9. codevs1907 方格取数 3

    «问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.«编程任务:对于给定的方格棋 ...

随机推荐

  1. 【占坑】IDEA从github 导入并运行 SpringBoot + VUE项目

    最近工程实践的项目内容是开发一个类似于博客和bbs论坛的系统,在github上找了一个类似的项目可以照着写一写.所以这里先占着坑,等把后端的数据库连接学完了再来填坑. github项目链接:githu ...

  2. c++拷贝构造函数引用传参

    看一道C++面试题: 给出下述代码,分析编译运行的结果,并提供3个选项: A.编译错误  B.编译成功,运行时程序崩溃  C.编译运行正常,输出10 class A { private: int va ...

  3. Linux_Day001-002章常用命令

    Linux操作系统的组成 以下符号的意义. 输出重定向和输入重定向的知识点 echo 把后面的文字显示出来 xargs 分组, -n 分为n组  xargs -n 1.txt (完整命令:xargs ...

  4. java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

    函数式接口详细定义 函数式接口只有一个抽象方法 由于default方法有一个实现,所以他们不是抽象的. 如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽 ...

  5. Winform中怎样根据Name获取同窗体的控件

    场景 在同一个Winform窗体中,点击一个Button按钮时, 获取同窗体的其他控件的属性. 首先需要对要获取的控件赋予Name属性,然后就可以通过Name进行获取. 实现 在Button的点击事件 ...

  6. 运行pytest,报错"AttributeError: 'module' object has no attribute 'xxx'"

    最近学习pytest被此问题困扰,敲脑壳,实在是不该.百度解决方法一大堆,我的问题怎么也解决不了,来看一下,我是怎么解决的,各位大佬勿喷,只是自己做笔记用,谢谢. 报错信息如下: 网上解决方法是这样的 ...

  7. 【读书笔记】C++ primer 5th 从入门到自闭(一)

    这几天看了C++ primer 5th的一二章,有很多收获,但是有的地方因为翻译的问题也搞得理解起来颇为难受啊啊啊啊.尤其是const限定符,在C语言并没有这么多复杂的语法,在C++里面语法细节就多的 ...

  8. 04: OpenGL ES 基础教程03 纹理

    前言 1:常用类: 1:纹理的作用 正文 一:常用类 上下文 顶点数据缓存 着色器 baseEffect 一:纹理 1.1:   纹理可以控制渲染的每个像素的颜色. 1.2: 纹素:与像素一样,保存每 ...

  9. 复习0824js

    编程思想: 面向过程:凡事亲力亲为,所有事情的过程都要清楚,注重的是过程. 面向对象:提出需求,找到对象,对象解决这个问题,我们要结果,注重的是结果. 面向对象的特性:封装,继承,多态: JS: 是一 ...

  10. Android手机QQ文件夹解析

    注:切勿修改手机QQ文件夹,以免造成不必要的使用问题及无法修复的数据丢失] 安卓手机QQ tencent文件夹解析 QQ下载的聊天背景:tencent→MobileQQ→system_backgrou ...