HashMap简单介绍
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表。
一、什么是哈希表
在讨论哈希表之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能
数组:采用一段连续的存储单元来存储数据。对于指定下标的查找,时间复杂度为O(1);通过给定值进行查找,需要遍历数组,逐一比对给定关键字和数组元素,时间复杂度为O(n),当然,对于有序数组,则可采用二分查找,插值查找,斐波那契查找等方式,可将查找复杂度提高为O(logn);对于一般的插入删除操作,涉及到数组元素的移动,其平均复杂度也为O(n)
线性链表:对于链表的新增,删除等操作(在找到指定操作位置后),仅需处理结点间的引用即可,时间复杂度为O(1),而查找操作需要遍历链表逐一进行比对,复杂度为O(n)
二叉树:对一棵相对平衡的有序二叉树,对其进行插入,查找,删除等操作,平均复杂度均为O(logn)。
哈希表:相比上述几种数据结构,在哈希表中进行添加,删除,查找等操作,性能十分之高,不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1),接下来我们就来看看哈希表是如何实现达到惊艳的常数阶O(1)的。
我们知道,数据结构的物理存储结构只有两种:顺序存储结构和链式存储结构(像栈,队列,树,图等是从逻辑结构去抽象的,映射到内存中,也这两种物理组织形式),而在上面我们提到过,在数组中根据下标查找某个元素,一次定位就可以达到,哈希表利用了这种特性,哈希表的主干就是数组。
比如我们要新增或查找某个元素,我们通过把当前元素的关键字 通过某个函数映射到数组中的某个位置,通过数组下标一次定位就可完成操作。
存储位置 = f(关键字)
其中,这个函数f一般称为哈希函数,这个函数的设计好坏会直接影响到哈希表的优劣。举个例子,比如我们要在哈希表中执行插入操作:

查找操作同理,先通过哈希函数计算出实际存储地址,然后从数组中对应地址取出即可。
哈希冲突
然而万事无完美,如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突,也叫哈希碰撞。前面我们提到过,哈希函数的设计至关重要,好的哈希函数会尽可能地保证 计算简单和散列地址分布均匀,但是,我们需要清楚的是,数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突。那么哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式,
二、HashMap实现原理
HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。
//HashMap的主干数组,可以看到就是一个Entry数组,初始值为空数组{},主干数组的长度一定是2的次幂,至于为什么这么做,后面会有详细分析。
transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
Entry是HashMap中的一个静态内部类。代码如下

static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;//存储指向下一个Entry的引用,单链表结构
int hash;//对key的hashcode值进行hash运算后得到的值,存储在Entry,避免重复计算
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}

所以,HashMap的整体结构如下
简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,急需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
详细介绍:http://www.cnblogs.com/chengxiao/p/6059914.html#t2
HashMap简单介绍的更多相关文章
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...
- Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- [freemarker篇]04.简单介绍-基本数据类型
好几天没有更新博客了,最近一顿乱七八糟的忙!今天简单更新第四章,这里只能说是简单介绍,因为权威的还是需要看Freemarker的官方中文手册! 好几天没有更新博客了,最近一顿乱七八糟的忙!今天简单更新 ...
- 简单介绍Struts2
Struts2概述 Struts2虽然是Struts1的基础上发展起来的,但是实质上是以WebWork框架为核心,为传统的Struts1注入了WebWork的设计理念,统一了Struts1和WebWo ...
- hashtable 简单介绍
Hashtable 1 注意小写 table 2 常用方法 void clear() boolean contains(Object value) ...
- 第一次玩博客,今天被安利了一个很方便JDBC的基于Spring框架的一个叫SimpleInsert的类,现在就来简单介绍一下
首先先对这段代码的简单介绍,我之前在需要操作JDBC的时候总是会因为经常要重新写SQL语句感到很麻烦.所以就能拿则拿不能拿的就简单地封装了一下. 首先是Insert.Spring框架的JDBC包里面的 ...
- Intent的作用和表现形式简单介绍
Intent的作用和表现形式简单介绍 1.描写叙述:Intent负责相应用中一次操作的动作,动作涉及的数据,附加数据进行描写叙述.系统或者应用依据此Intent的描写叙述,负责找到相应的组件,将Int ...
- 关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
随机推荐
- 【opencv源码解析】 三、resize
resize.cpp void cv::resize( InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, doubl ...
- Ubuntu18.04安装MySQL与默认编码设置
安装 打开终端直接开始,编码配置方法在后面 #通过apt更新包索引 sudo apt update #按照默认软件包安装 sudo apt install mysql-server #运行安全脚本 s ...
- input type=color 设置颜色
在设置背景色的时候,使用html5 type=color 标签,但是初始值一直都是黑色的,背景如果没有设置的时候,应该是白色,比如文本图元,所以需要设置一个初始的颜色值, 注意: value不实用,怎 ...
- selenium无头浏览器&规避操作
一.无头浏览器概述: 无头浏览器主要目的是打开浏览器但用户看不到 简单用法如下: from selenium import webdriver from time import sleep from ...
- 今日js心得
<input type="hidden" id="history_chart_json" data-json="#{smartDeviceMon ...
- printf颜色
格式 printf("\033[?m%s\033[0m", str); 多个属性以:分隔 属性: \033[0m:关闭所有属性 \033[1m:设置高亮度 \033[4m:下划线 ...
- 常见python面试题-手写代码系列
1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reversetempList = [1,2,3,4]tempList.reverse()for x in tempList: pr ...
- 【2】Git仓库
一.获取 Git 仓库 初始化仓库 ##基于当前目录初始化仓库 $ git init ##指定demo目录初始化仓库 $ git init demo 克隆现有仓库 ##克隆现有的仓库,默认目录名:li ...
- 微信公众号开发(三)—— access_token的管理
上一篇 微信公众号开发(二)—— 微信公众平台接入 让我们的本地工程顺利的接入到微信公众号系统, 那么接下啦我们介绍一个很重要的感念——acess_token (access_token是公众号的全局 ...
- vim文本编辑及文件查找应用3
文件查找 locate,find两个命令 在文件系统上查找符合条件的文件: 实现工具:locate,find locate命令: 依赖于事先构建好的索引库,索引库可以由下边两种方式构建 系统自动实现( ...