1.hashmap的实现

  ① 初始化

    1)定义一个Node<K, V>的数组来存放元素,但不立即初始化,在使用的时候再加载

    2)定义数组初始大小为16

    3)定义负载因子,默认为0.75,

    4)定义size用来记录容器存放的元素数量

  ② put的实现思路

    1)  判断容器是否为空,为空则初始化。

    2)判断容器的size是否大于阀值,是的话就扩容为以前长度的两倍,并重新计算其中元素的存放位置,进行重新存放

    3)计算出key的index角标位置

    4)判断计算出的index位置是否存在元素,存在的话则遍历链表,判断key是否存在,存在则更新,不存在则增加

  ③ get的实现思路

    1)通过key计算出它所在的index

    2)遍历index位置处的链表,并获取value返回。

  1. package com.test;
  2.  
  3. /**
  4. * 自定义hashMap
  5. * @author cf
  6. *
  7. * @param <K>
  8. * @param <V>
  9. */
  10. public class MyHashMap<K, V> implements MyMap<K, V>{
  11. //1.定义一个容器用来存放元素, 但不立即初始化,使用懒加载方式
  12. Node<K, V>[] table = null;
  13.  
  14. //2.定义容器的默认大小
  15. static int DEFAULT_INITIAL_CAPACITY = 16;
  16.  
  17. //3.HashMap默认负载因子,负载因子越小,hash冲突机率越低,综合结论得出0.75最为合适
  18. static final float DEFAULT_LOAD_FACTOR = 0.75f;
  19.  
  20. //4.记录当前容器实际大小
  21. static int size;
  22.  
  23. @SuppressWarnings("unchecked")
  24. @Override
  25. public V put(K k, V v) {
  26. //1.判断容器是否为空为空则初始化。
  27. if (table == null) {
  28. table = new Node[DEFAULT_INITIAL_CAPACITY];
  29. }
  30.  
  31. //如果size大于阈值则进行扩容
  32. if (size > DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR) {
  33. resize();
  34. }
  35.  
  36. //2.计算出index角标
  37. int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
  38.  
  39. //3.将k-v键值对放进相对应的角标,如果计算出角标相同则以链表的形势存放
  40. Node<K, V> node = table[index];
  41. if (node == null) {
  42. table[index] = new Node<>(k, v, null);
  43. size ++;
  44. return table[index].getValue();
  45. } else {
  46. Node<K, V> newNode = node;
  47.  
  48. //循环遍历每个节点看看是否存在相同的key
  49. while (newNode != null) {
  50. //这里要用equals 和 == 因为key有可能是基本数据类型,也有可能是引用类型
  51. if (k.equals(newNode.getKey()) || k == newNode.getKey()) {
  52. newNode.setValue(v);
  53. size ++;
  54. return v;
  55. }
  56. newNode = node.getNextNode();
  57. }
  58. table[index] = new Node<K, V>(k, v, table[index]);
  59. size ++;
  60.  
  61. return table[index].getValue();
  62. }
  63.  
  64. }
  65.  
  66. /**
  67. * 获取index
  68. * @param key
  69. * @param length
  70. * @return
  71. */
  72. public int getIndex(K key, int length) {
  73. int hashCode = key.hashCode();
  74. int index = hashCode % length;
  75. return index;
  76. }
  77.  
  78. /**
  79. * 获取key
  80. */
  81. @Override
  82. public V get(K k) {
  83. int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
  84. Node<K, V> node = table[index];
  85. if (k.equals(node.getKey()) || k == node.getKey()) {
  86. return node.getValue();
  87. } else {
  88. Node<K, V> nextNode = node.getNextNode();
  89. while(nextNode != null) {
  90. if (k.equals(nextNode.getKey()) || k == nextNode.getKey()) {
  91. return nextNode.getValue();
  92. }
  93. }
  94. }
  95. return null;
  96. }
  97.  
  98. /**
  99. * 对size进行扩容
  100. */
  101. @SuppressWarnings("unchecked")
  102. public void resize() {
  103. //1.创建新的table长度扩展为以前的两倍
  104. int newLength = DEFAULT_INITIAL_CAPACITY * 2;
  105. Node<K, V>[] newtable = new Node[newLength];
  106. //2.将以前table中的取出,并重新计算index存入
  107. for (int i = 0; i < table.length; i++) {
  108. Node<K, V> oldtable = table[i];
  109. while (oldtable != null) {
  110. //将table[i]的位置赋值为空,
  111. table[i] = null;
  112.  
  113. //方法1:重新计算index,然后按照put时候的方法进行放值,此种方法会不停的new 对象会造成效率比较低
  114. /*K key = oldtable.getKey();
  115. int index = getIndex(key, newLength);
  116. newtable[index] = new Node<K, V>(key, oldtable.getValue(), newtable[index]);
  117. oldtable = oldtable.getNextNode();*/
  118.  
  119. //方法2:
  120. //计算新的index值
  121. K key = oldtable.getKey();
  122. int index = getIndex(key, newLength);
  123.  
  124. //将以前的nextnode保存下来
  125. Node<K, V> nextNode = oldtable.getNextNode();
  126.  
  127. //将newtable的值赋值在oldtable的nextnode上,如果以前是空,则nextnode也是空
  128. oldtable.setNextNode(newtable[index]);
  129. newtable[i] = oldtable;
  130.  
  131. //将以前的nextcode赋值给oldtable以便继续遍历
  132. oldtable = nextNode;
  133. }
  134.  
  135. }
  136.  
  137. //3.将新的table赋值回老的table
  138. table = newtable;
  139. DEFAULT_INITIAL_CAPACITY = newLength;
  140. newtable = null;
  141.  
  142. }
  143.  
  144. @Override
  145. public int size() {
  146. return size;
  147. }
  148.  
  149. @SuppressWarnings("hiding")
  150. class Node<K, V> implements Entry<K, V> {
  151. private K key;
  152. private V value;
  153. private Node<K, V> nextNode; //下一节点
  154.  
  155. public Node(K key, V value, Node<K, V> nextNode) {
  156. super();
  157. this.key = key;
  158. this.value = value;
  159. this.nextNode = nextNode;
  160. }
  161.  
  162. @Override
  163. public K getKey() {
  164. return this.key;
  165. }
  166.  
  167. @Override
  168. public V getValue() {
  169. return this.value;
  170. }
  171.  
  172. @Override
  173. public void setValue(V value) {
  174. this.value = value;
  175. }
  176.  
  177. public Node<K, V> getNextNode() {
  178. return nextNode;
  179. }
  180.  
  181. public void setNextNode(Node<K, V> nextNode) {
  182. this.nextNode = nextNode;
  183. }
  184.  
  185. public void setKey(K key) {
  186. this.key = key;
  187. }
  188.  
  189. //判断是否还有下一个节点
  190. /*private boolean hasNext() {
  191. return true;
  192. }*/
  193.  
  194. }
  195.  
  196. // 测试方法.打印所有的链表元素
  197. public void print() {
  198. for (int i = 0; i < table.length; i++) {
  199. Node<K, V> node = table[i];
  200. System.out.print("下标位置[" + i + "]");
  201. while (node != null) {
  202. System.out.print("[ key:" + node.getKey() + ",value:" + node.getValue() + "]");
  203. node = node.nextNode;
  204. }
  205. System.out.println();
  206. }
  207.  
  208. }
  209.  
  210. }

2.测试代码

  1. package com.test;
  2.  
  3. public class TestMap {
  4. public static void main(String[] args) {
  5. MyHashMap<String, String> extHashMap = new MyHashMap<String, String>();
  6. extHashMap.put("1号", "1号");//
  7. extHashMap.put("2号", "1号");//
  8. extHashMap.put("3号", "1号");//
  9. extHashMap.put("4号", "1号");//
  10. extHashMap.put("6号", "1号");//
  11. extHashMap.put("7号", "1号");
  12. extHashMap.put("14号", "1号");
  13.  
  14. extHashMap.put("22号", "1号");
  15. extHashMap.put("26号", "1号");
  16. extHashMap.put("27号", "1号");
  17. extHashMap.put("28号", "1号");
  18. extHashMap.put("66号", "66");
  19. extHashMap.put("30号", "1号");
  20. System.out.println("扩容前数据....");
  21. extHashMap.print();
  22. System.out.println("扩容后数据....");
  23. extHashMap.put("31号", "1号");
  24. extHashMap.put("66号", "123466666");
  25. extHashMap.print();
  26. // 修改3号之后
  27. System.out.println(extHashMap.get("66号"));
  28.  
  29. }
  30. }

如有疑问或错误请在下方留言指出!  谢谢大佬

纯手写实现HashMap的更多相关文章

  1. springmvc 动态代理 JDK实现与模拟JDK纯手写实现。

    首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用  ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Pr ...

  2. 简易-五星评分-jQuery纯手写

    超级简单的评分功能,分为四个步骤轻松搞定: 第一步: 引入jquery文件:这里我用百度CDN的jquery: <script src="http://apps.bdimg.com/l ...

  3. vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件

    vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源 ...

  4. 超级简单的jQuery纯手写五星评分效果

    超级简单的评分功能,分为四个步骤轻松搞定: 第一步: 引入jquery文件:这里我用百度CDN的jquery: <script src="http://apps.bdimg.com/l ...

  5. 纯手写Myatis框架

    1.接口层-和数据库交互的方式 MyBatis和数据库的交互有两种方式: 使用传统的MyBatis提供的API: 使用Mapper接口: 2.使用Mapper接口 MyBatis 将配置文件中的每一个 ...

  6. 3 手写Java HashMap核心源码

    手写Java HashMap核心源码 上一章手写LinkedList核心源码,本章我们来手写Java HashMap的核心源码. 我们来先了解一下HashMap的原理.HashMap 字面意思 has ...

  7. SQL纯手写创建数据库到表内内容

    建表啥的只点点鼠标,太外行了,不如来看看我的纯手写,让表从无到有一系列:还有存储过程临时表,不间断的重排序: 一:建数据库 create Database Show on primary ( name ...

  8. 纯手写SpringMVC到SpringBoot框架项目实战

    引言 Spring Boot其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. 通过这种方式,springboot ...

  9. 纯手写SpringMVC架构,用注解实现springmvc过程

    1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping 第二步:完成对应的anno ...

随机推荐

  1. “全栈2019”Java第三十八章:类与方法

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  2. [BZOJ1935][SHOI2007]Tree 园丁的烦恼(树状数组)

    题目描述 很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草. 有一天国王漫步在花园里,若有所思,他问一个园丁道: “最近我在思 ...

  3. Jmeter后置处理器之JSON Extractor

    一.使用场景 json extractor后置处理器用在返回格式为json的HTTP请求中,用来获取返回的json中的某个值.并保存成变量供后面的请求进行调用或断言等. 二.使用方法 步骤一:选择HT ...

  4. es去重查询

    {     "query": {                 "bool": {                     "must": ...

  5. leetcode-806-Number of Lines To Write String

    题目描述: We are to write the letters of a given string S, from left to right into lines. Each line has ...

  6. Codeforces Round #556 题解

    Codeforces Round #556 题解 Div.2 A Stock Arbitraging 傻逼题 Div.2 B Tiling Challenge 傻逼题 Div.1 A Prefix S ...

  7. 基础篇:6.4)形位公差-基准 Datum

    本章目标:了解形位公差基准及运用. 1.定义: 基准 —  与被测要素有关且用来定义其几何位置关系的一个几何理想要素(如轴线.直线.平面等): —  可由零件上的一个或多个基准要素构成. 模拟基准要素 ...

  8. crontab例行性共作

    一.单一工作调度 at [-mldv] TIME at -c 工作号码 -m:当at工作结束后,即是没有输出信息,以email通知用户该工作已完成 -l:at -l相当于atq,列出目前系统上所有的a ...

  9. ORACLE INSERT ALL 用法

    1INSERT ALL 1.1句法 multi_table_insert :: = conditional_insert_clause :: = 1.2multi_table_insert 在多表插入 ...

  10. Python+Selenium之常用模块

    要用webdriver:from selenium import webdriver eg: driver = webdriver.Chrome()      driver.maximize_wind ...