p.p1 { margin: 0; font: 11px Monaco }
p.p2 { margin: 0; font: 11px Monaco; min-height: 15px }
p.p3 { margin: 0; font: 11px Monaco; color: rgba(79, 118, 203, 1) }
p.p4 { margin: 0; font: 11px Monaco; color: rgba(147, 26, 104, 1) }
p.p5 { margin: 0; font: 11px Monaco; color: rgba(119, 119, 119, 1) }
p.p6 { margin: 0; font: 11px Monaco; color: rgba(126, 80, 79, 1) }
p.p7 { margin: 0; font: 11px Monaco; color: rgba(78, 144, 114, 1) }
span.s1 { color: rgba(147, 26, 104, 1) }
span.s2 { color: rgba(145, 175, 203, 1) }
span.s3 { text-decoration: underline; color: rgba(145, 175, 203, 1) }
span.s4 { text-decoration: underline }
span.s5 { color: rgba(0, 0, 0, 1) }
span.s6 { color: rgba(3, 38, 204, 1) }
span.s7 { color: rgba(126, 80, 79, 1) }
span.s8 { color: rgba(78, 144, 114, 1) }
span.Apple-tab-span { white-space: pre }

import java.util.AbstractMap;

import java.util.HashSet;

import java.util.LinkedList;

import java.util.ListIterator;

import java.util.Map;

import java.util.Set;

/**

记得很早之前看到过一篇帖子 说一个面试者去面试 某大厂要他当场写一个hashmap,其实今天讲的这个例子,足以应付那场面试,核心思想一应俱全,有些地方还欠完善。。。

这个simpleHashmap原理是如下实现

put:

首先定义一个基于链表的Entry hash桶数组

通过key的hashcode取模数组大小得到对应的hash桶下标

如果链表中没有找到对应的key 则加入当前hash桶中

否则覆盖Entry对象

get:

1.通过key的hashcode取模数组大小得到对应的hash桶

判断hash桶中是否存在Entry对象 有取出;没有返回null.

<br>

以下是实际hashmap实现思路:

以Entry[]数组实现的哈希桶数组,用Key的哈希值取模桶数组的大小可得到数组下标。

插入元素时,如果两条Key落在同一个桶(比如哈希值1和17取模16后都属于第一个哈希桶),我们称之为哈希冲突。

JDK的做法是链表法,Entry用一个next属性实现多个Entry以单向链表存放。查找哈希值为17的key时,先定位到哈希桶,然后链表遍历桶里所有元素,逐个比较其Hash值然后key值。

在JDK8里,新增默认为8的阈值,当一个桶里的Entry超过閥值,就不以单向链表而以红黑树来存放以加快Key的查找速度。

当然,最好还是桶里只有一个元素,不用去比较。所以默认当Entry数量达到桶数量的75%时,哈希冲突已比较严重,就会成倍扩容桶数组,并重新分配所有原来的Entry。扩容成本不低,所以也最好有个预估值。

取模用与操作(hash & (arrayLength-1))会比较快,所以数组的大小永远是2的N次方, 你随便给一个初始值比如17会转为32。默认第一次放入元素时的初始值是16。

iterator()时顺着哈希桶数组来遍历,看起来是个乱序

*

*

*/

public class SimpleHashMap<K, V> extends AbstractMap<K, V> {

static final int SIZE = 997;

LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];

@Override

public V put(K key, V value) {

V oldValue = null;

int index = Math.abs(key.hashCode()) % SIZE;// 取模

if (buckets[index] == null) {

buckets[index] = new LinkedList<MapEntry<K, V>>();

}

LinkedList<MapEntry<K, V>> bucket = buckets[index];// 桶位【槽位】

MapEntry<K, V> pair = new MapEntry<K, V>(key, value);

boolean found = false;

ListIterator<MapEntry<K, V>> it = bucket.listIterator();

while (it.hasNext()) {

MapEntry<K, V> iPair = it.next();

if (iPair.getKey().equals(key)) {

oldValue = iPair.getValue();

it.set(pair);

found = true;

break;

}

}

if (!found) {

bucket.add(pair);

}

return oldValue;

}

@Override

public V get(Object key) {

int index = Math.abs(key.hashCode()) % SIZE;

if (buckets[index] == null) {

return null;

}

for (MapEntry<K, V> iPair : buckets[index]) {

if (iPair.getKey().equals(key)) {

return iPair.getValue();

}

}

return null;

}

@Override

public Set<Map.Entry<K, V>> entrySet() {

Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K, V>>();

for (LinkedList<MapEntry<K, V>> bucket : buckets) {

if (bucket == null) {

continue;

}

for (MapEntry<K, V> mpair : bucket) {

set.add(mpair);

}

}

return set;

}

public static void main(String[] args) {

// SimpleHashMap<String, String> simpleHashMap=new SimpleHashMap<String,String>();

// simpleHashMap.putAll(Countries.capitals(25));

// System.out.println(simpleHashMap);

// System.out.println(simpleHashMap.get("ERITREA"));

// System.out.println(simpleHashMap.entrySet());

System.out.println(1 ^ 1); // 两个二进制比较 相同取0 不同为一

}

}

hashmap简单实现的更多相关文章

  1. JVM&NIO&HashMap简单问

    JVM&NIO&HashMap简单问 背景:前几天在网上看到关于JVM&NIO&HashMap的一些连环炮的面试题,整理下以备不时之需. 一.JVM Java的虚拟机的 ...

  2. 哈希表原理及hashmap简单实现

    哈希表也叫做散列表.在各种语言中都有hashmap的实现.其最突出的优点是查找和插入以及删除具有常数的时间复杂度 我们可以把哈希表理解为数组+链表 数组具有常数复杂度的查找,为什么呢,因为数组是在内存 ...

  3. HashMap简单介绍

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表. 一.什么是哈希表 在讨论哈希表之 ...

  4. HashMap简单理解

    1. hashmap基于哈希表的map接口实现,此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable ...

  5. hashmap简单实例(个人使用经验)

    一.HashMap<int,String>是错误的:因为int是基本类型,而key和value要求是对象,所以要用Integer而不是int.HashMap<String,Objec ...

  6. java集合框架(1) hashMap 简单使用以及深度分析(转)

    java.util 类 HashMap<K,V>java.lang.Object  java.util.AbstractMap<K,V>      java.util.Hash ...

  7. java集合框架 hashMap 简单使用

    参考文章:http://blog.csdn.net/itm_hadf/article/details/7497462 通常,默认加载因子 (.75) 在时间和空间成本上寻求一种折衷.      加载因 ...

  8. 关于Android中ArrayMap/SparseArray比HashMap性能好的深入研究

    由于网上有朋友对于这个问题已经有了很详细的研究,所以我就不班门弄斧了: 转载于:http://android-performance.com/android/2014/02/10/android-sp ...

  9. 【Java】HashMap源码分析——基本概念

    在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...

随机推荐

  1. centos7中安装redis出现的问题

    重现步骤: 1.解压redis包后 执行make命令.出现一堆东西,其中有gcc:命令未找到. 解决:安装 yum install gcc-c++(需要有网) 2.安装完gcc命令后,再make.出现 ...

  2. moviepy音视频开发:音频文件存取类AudioFileClip属性和方法介绍

    ☞ ░ 前往老猿Python博文目录 ░ 一.概述 AudioFileClip是AudioClip的直接子类,用于从一个音频文件或音频数组中读入音频到内存构建音频剪辑.但AudioFileClip并不 ...

  3. PyQt(Python+Qt)学习随笔:窗口对象尺寸调整相关的函数resize、showMaximized、showNormal、showMinimized

    resize(width,height) resize可以直接调整窗口的尺寸,调整效果类似于鼠标直接拉伸或缩小窗口,但窗口大小的最大值.最小值受窗口的sizePolicy.sizeHint.minim ...

  4. 在.Net中所有可序列化的类都被标记为_

    [Serializable] 这个叫Attribute写在类.属性.字段的上面,比如 [Serializable] class A { ... }

  5. Proxy:简单小巧又强大好用的代理系统

    之前的文章介绍了许多我们在用的DevOps相关的工具系统,例如:方便创建多套运行环境的Alodi,对运维友好的配置中心Kerrigan,强大的自定义任务引擎Probius以及专注于数据库自动化的ove ...

  6. 搭建yum仓库服务器

    环境:服务端centos6.9 客户端要求 能上网(可以ping通baidu.com) 1.yum的配置文件信息在/etc/yum.repos.d/下,我们配置的是自己的网络yum源,所以这些文件我们 ...

  7. 代理ip知识

    一.没有使用代理服务器的情况: REMOTE_ADDR = 您的 IP      HTTP_VIA = 没数值或不显示      HTTP_X_FORWARDED_FOR = 没数值或不显示 二.使用 ...

  8. 数据结构与算法——图(游戏中的自动寻路-A*算法)

    在复杂的 3D 游戏环境中如何能使非玩家控制角色准确实现自动寻路功能成为了 3D 游戏开 发技术中一大研究热点.其中 A*算法得到了大量的运用,A*算法较之传统的路径规划算法,实时性更高.灵活性更强, ...

  9. screw一键生成数据库文档

    1. 简介   在项目开发和交付阶段,数据库文档是必不可少的.对于大型项目多个数据库几百甚至几千张表来说,手写数据库文档必然是耗时且痛苦的.因此需要一个插件自动生成文档.   screw提供了多种文件 ...

  10. ssl证书---验证等级分类

    DV SSL证书(domain Validation SSL): 指只验证网站域名所有权的简易型SSL证书,此类证书仅能起到网站机密信息加密的作用,无法向用户证明网站的真实身份.所以,不推荐在电子商务 ...