【2021春招】HashMap图解原理与数据结构一【JDK7】

2,018 阅读4分钟

面试被虐

你好,早上、中午、下午、晚上好。我是一名无缘985,日常996工程师。

作为一名为人民币服务的工程师,学好技术是多么重要的事情。

今天跟各位老铁们详细说说日常的开发中经常用到的HashMap。

怎么可能骗你,真的哦,无论我们在开发中还是在面试的时候HashMap必问好不好。上次一位同事去熊厂,就被面试官问到了,被虐的体无完肤。

哼哼哼哼哼~哼~~~~

这不,今天来现场教学了。

首先我们快速回忆下我们日常开发中怎么使用hashmap的。

快速开始

public class App {
   public static void main(String[] args) {
      //Map map = new HashMap<>();
      App map=new App();
      map.put("刘一", "刘一");
      map.put("陈二", "陈二");
      map.put("张三", "张三");
      map.put("李四", "李四");
      map.put("王五", "王五");
      map.put("java_jiagou", "微信搜:java大型网站架构");
      System.out.println(map.get("java_jiagou"));
   }

hashmap在我们日常工作一般用的多的就是其put方法和get方法。

技术本质

现在我们已经对hashmap有一个大致的了解了,接下来我们要去了解其底层的原理,也就是本质。 在这里插入图片描述

很多朋友在面试的时候经常被问到hashmap底层实现原理?都说是数据+链表 ok!估计大家都会被了 但是真正知道底层如何存储的我相信不多,不急 我们来看下数组和链表的定义

数组

数组:采用一段连续的存储单元来存储数据。对于指定下标的查找,时间复杂度为O(1);对于一般的插入删除操作, 涉及到数组元素的移动,其平均复杂度也为O(n)

在这里插入图片描述

Java代码表示

   //数组:采用一段连续的存储单元来存储数据。
   //特点:指定下标O(1) 删除插入O(N) 数组:查询快 插入慢 ArrayList
   public static void main(String[] args) {
      Integer[] integers = new Integer[10];
      integers[0]=0;//王五
      integers[1]=1;
      integers[2]=2;
      integers[9]=9;

链表

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

对于链表的新增,删除等操作(在找到指定操作位置后),仅需处理结点间的引用即可,时间复杂度为O(1),

而查找操作需要遍历链表逐一进行比对,复杂度为O(n)

在这里插入图片描述

public class Node {

   public Node  next;
   private Object data;

   public Node(Object data) {
      this.data = data;
   }
   //链表:链表是一种物理存储单元上非连续、非顺序的存储结构
   //特点:插入、删除时间复杂度O(1) 查找遍历时间复杂度0(N) 插入快 查找慢
   public static void main(String[] args) {
         Node node=new Node(15);
         node.next=new Node(1);
         node.next.next=new Node(9);
   }

哈希算法

哈希算法(也叫散列),就是把任意长度值(Key)通过散列算法变换成固定长度的key地址,通过这个地址进行访问的数据结构。 它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。 在这里插入图片描述

实现原理PUT

刚才我们分析了hashmap由数组+链表构成,介绍了数组+链表的描述,接下来我们就把这两个数据结构整合在一起吧,在整合在一起。

我们写一个伪put代码,目的是看hahsmap底层存储

 /***
    * 输出  key value hashcode 等 hash算法
    * @param key
    * @param value
    */
   public void put(String key, String value) {
      //hash函数
      System.out.printf("key:%s,hash值:%s,存储位置:%s\r\n", key, key.hashCode(), Math.abs(key.hashCode() % 15));
   }

运行代码如下

key:刘一,hash值:671464,存储位置:4
key:陈二,hash值:1212740,存储位置:5
key:张三,hash值:774889,存储位置:4
key:李四,hash值:842061,存储位置:6
key:王五,hash值:937065,存储位置:0
key:java_jiagou,hash值:1185548040,存储位置:0

对应的图形存储结构就是:

1. 初始化:

在这里插入图片描述

2. 第一次put:

这次put“刘一” 存放在下标为4的数组上,对象类型是

class Entry<K, V>
      K k;
      V v;
      int hash;
      Entry<K, V> next;

key:刘一,hash值:671464,存储位置:4

在这里插入图片描述

第二次put:

这次put“陈二” 存放在下标为5的数组上

key:陈二,hash值:1212740,存储位置:5 在这里插入图片描述

第三次put:

这次次put“张三” 存放在下标为4的数组上,可是下标为4已经有“刘一”了,如果暴力存储会出问题的呀。 别急嘛,我们刚才不是还学了链表嘛。这个时候该链表上场了。

key:张三,hash值:774889,存储位置:4

在这里插入图片描述

第N次put:

我相信通过前几次的put大家都会put了吧,最后存储结构是这样的。 在这里插入图片描述

实现原理GET

我们put是根据hash算法定位到数组下标的,那我们get怎么找到他们了?非常简单嘛原路去找。

尽然可以通过hash算法put,肯定也可以通过hash算法get到嘛。A点尽然可以到B点,那自然B点也可以到A点嘛。示范一个,只示范一个。

在这里插入图片描述

实现

听懂了嘛?

总结

好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是牛人。那我在布置个作业吧。 根据我们图形的演示,你能手写实现吗?

我提示下

public interface Map<K,V> {
   public V put(K k,V v);
   public V get(K k);
   public int size();
   interface Entry<K,V>{
      public K getKey();
      public V getValue();
   }
}

供免费的学习资料,学习技术内容包含有:Spring,Dubbo,MyBatis, RPC,源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

需要的朋友可以点击:点这个,点这个,暗号:j j 。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2020年最新大厂面试题。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述