纯手写实现HashMap
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返回。
package com.test; /**
* 自定义hashMap
* @author cf
*
* @param <K>
* @param <V>
*/
public class MyHashMap<K, V> implements MyMap<K, V>{
//1.定义一个容器用来存放元素, 但不立即初始化,使用懒加载方式
Node<K, V>[] table = null; //2.定义容器的默认大小
static int DEFAULT_INITIAL_CAPACITY = 16; //3.HashMap默认负载因子,负载因子越小,hash冲突机率越低,综合结论得出0.75最为合适
static final float DEFAULT_LOAD_FACTOR = 0.75f; //4.记录当前容器实际大小
static int size; @SuppressWarnings("unchecked")
@Override
public V put(K k, V v) {
//1.判断容器是否为空为空则初始化。
if (table == null) {
table = new Node[DEFAULT_INITIAL_CAPACITY];
} //如果size大于阈值则进行扩容
if (size > DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR) {
resize();
} //2.计算出index角标
int index = getIndex(k, DEFAULT_INITIAL_CAPACITY); //3.将k-v键值对放进相对应的角标,如果计算出角标相同则以链表的形势存放
Node<K, V> node = table[index];
if (node == null) {
table[index] = new Node<>(k, v, null);
size ++;
return table[index].getValue();
} else {
Node<K, V> newNode = node; //循环遍历每个节点看看是否存在相同的key
while (newNode != null) {
//这里要用equals 和 == 因为key有可能是基本数据类型,也有可能是引用类型
if (k.equals(newNode.getKey()) || k == newNode.getKey()) {
newNode.setValue(v);
size ++;
return v;
}
newNode = node.getNextNode();
}
table[index] = new Node<K, V>(k, v, table[index]);
size ++; return table[index].getValue();
} } /**
* 获取index
* @param key
* @param length
* @return
*/
public int getIndex(K key, int length) {
int hashCode = key.hashCode();
int index = hashCode % length;
return index;
} /**
* 获取key
*/
@Override
public V get(K k) {
int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
Node<K, V> node = table[index];
if (k.equals(node.getKey()) || k == node.getKey()) {
return node.getValue();
} else {
Node<K, V> nextNode = node.getNextNode();
while(nextNode != null) {
if (k.equals(nextNode.getKey()) || k == nextNode.getKey()) {
return nextNode.getValue();
}
}
}
return null;
} /**
* 对size进行扩容
*/
@SuppressWarnings("unchecked")
public void resize() {
//1.创建新的table长度扩展为以前的两倍
int newLength = DEFAULT_INITIAL_CAPACITY * 2;
Node<K, V>[] newtable = new Node[newLength];
//2.将以前table中的取出,并重新计算index存入
for (int i = 0; i < table.length; i++) {
Node<K, V> oldtable = table[i];
while (oldtable != null) {
//将table[i]的位置赋值为空,
table[i] = null; //方法1:重新计算index,然后按照put时候的方法进行放值,此种方法会不停的new 对象会造成效率比较低
/*K key = oldtable.getKey();
int index = getIndex(key, newLength);
newtable[index] = new Node<K, V>(key, oldtable.getValue(), newtable[index]);
oldtable = oldtable.getNextNode();*/ //方法2:
//计算新的index值
K key = oldtable.getKey();
int index = getIndex(key, newLength); //将以前的nextnode保存下来
Node<K, V> nextNode = oldtable.getNextNode(); //将newtable的值赋值在oldtable的nextnode上,如果以前是空,则nextnode也是空
oldtable.setNextNode(newtable[index]);
newtable[i] = oldtable; //将以前的nextcode赋值给oldtable以便继续遍历
oldtable = nextNode;
} } //3.将新的table赋值回老的table
table = newtable;
DEFAULT_INITIAL_CAPACITY = newLength;
newtable = null; } @Override
public int size() {
return size;
} @SuppressWarnings("hiding")
class Node<K, V> implements Entry<K, V> {
private K key;
private V value;
private Node<K, V> nextNode; //下一节点 public Node(K key, V value, Node<K, V> nextNode) {
super();
this.key = key;
this.value = value;
this.nextNode = nextNode;
} @Override
public K getKey() {
return this.key;
} @Override
public V getValue() {
return this.value;
} @Override
public void setValue(V value) {
this.value = value;
} public Node<K, V> getNextNode() {
return nextNode;
} public void setNextNode(Node<K, V> nextNode) {
this.nextNode = nextNode;
} public void setKey(K key) {
this.key = key;
} //判断是否还有下一个节点
/*private boolean hasNext() {
return true;
}*/ } // 测试方法.打印所有的链表元素
public void print() {
for (int i = 0; i < table.length; i++) {
Node<K, V> node = table[i];
System.out.print("下标位置[" + i + "]");
while (node != null) {
System.out.print("[ key:" + node.getKey() + ",value:" + node.getValue() + "]");
node = node.nextNode;
}
System.out.println();
} } }
2.测试代码
package com.test; public class TestMap {
public static void main(String[] args) {
MyHashMap<String, String> extHashMap = new MyHashMap<String, String>();
extHashMap.put("1号", "1号");//
extHashMap.put("2号", "1号");//
extHashMap.put("3号", "1号");//
extHashMap.put("4号", "1号");//
extHashMap.put("6号", "1号");//
extHashMap.put("7号", "1号");
extHashMap.put("14号", "1号"); extHashMap.put("22号", "1号");
extHashMap.put("26号", "1号");
extHashMap.put("27号", "1号");
extHashMap.put("28号", "1号");
extHashMap.put("66号", "66");
extHashMap.put("30号", "1号");
System.out.println("扩容前数据....");
extHashMap.print();
System.out.println("扩容后数据....");
extHashMap.put("31号", "1号");
extHashMap.put("66号", "123466666");
extHashMap.print();
// 修改3号之后
System.out.println(extHashMap.get("66号")); }
}
如有疑问或错误请在下方留言指出! 谢谢大佬
纯手写实现HashMap的更多相关文章
- springmvc 动态代理 JDK实现与模拟JDK纯手写实现。
首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用 ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Pr ...
- 简易-五星评分-jQuery纯手写
超级简单的评分功能,分为四个步骤轻松搞定: 第一步: 引入jquery文件:这里我用百度CDN的jquery: <script src="http://apps.bdimg.com/l ...
- vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件
vue10行代码实现上拉翻页加载更多数据,纯手写js实现下拉刷新上拉翻页不引用任何第三方插件/库 一提到移动端的下拉刷新上拉翻页,你可能就会想到iScroll插件,没错iScroll是一个高性能,资源 ...
- 超级简单的jQuery纯手写五星评分效果
超级简单的评分功能,分为四个步骤轻松搞定: 第一步: 引入jquery文件:这里我用百度CDN的jquery: <script src="http://apps.bdimg.com/l ...
- 纯手写Myatis框架
1.接口层-和数据库交互的方式 MyBatis和数据库的交互有两种方式: 使用传统的MyBatis提供的API: 使用Mapper接口: 2.使用Mapper接口 MyBatis 将配置文件中的每一个 ...
- 3 手写Java HashMap核心源码
手写Java HashMap核心源码 上一章手写LinkedList核心源码,本章我们来手写Java HashMap的核心源码. 我们来先了解一下HashMap的原理.HashMap 字面意思 has ...
- SQL纯手写创建数据库到表内内容
建表啥的只点点鼠标,太外行了,不如来看看我的纯手写,让表从无到有一系列:还有存储过程临时表,不间断的重排序: 一:建数据库 create Database Show on primary ( name ...
- 纯手写SpringMVC到SpringBoot框架项目实战
引言 Spring Boot其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置. 通过这种方式,springboot ...
- 纯手写SpringMVC架构,用注解实现springmvc过程
1.第一步,首先搭建如下架构,其中,annotation中放置自己编写的注解,主要包括service controller qualifier RequestMapping 第二步:完成对应的anno ...
随机推荐
- word的xml文件中给文字添加超链
<w:hlink w:dest="http://xxx.com"><w:r></w:r></wr></w:hlink>& ...
- noip提高组模拟赛(QBXT)T2
T2count题解 [ 问题描述]: 小 A 是一名热衷于优化各种算法的 OIER,有一天他给了你一个随机生成的 1~n 的排列, 并定 义区间[l,r]的价值为: \[ \huge C_{l,r}= ...
- SAP生产订单各种日期的计算说明
生产订单各种日期的计算说明 基本日期.已计划的.确认的日期,介绍一下这些日期的作用和计算方法: 首先我们来介绍一下基本日期: 基本开始日期:表示订单的开始日期 基本完成日期:表示订单的完成日期 我们在 ...
- 大数据-zookeeper集群安装
一.安装前发现的问题: 1.安装前期发现jps权限不够 [root@master1 ~]# jps -bash: /opt/workspace/jdk1./bin/jps: Permission de ...
- react-router的简单使用
React Router是一个基于React之上的强大路由库,可以让你向应用中快速的添加视图和数据流,同时保持页面与URL间的同步. 1.安装: npm install --save react-ro ...
- MyEclipse配置,每次打开server中都没有weblogic
最近在myeclipse新配了个weblogic,结果每次打开myeclipse在server中都看不到weblogic,得重新去配置页面走一遭才能出现.很麻烦. 后来在网上找了找,找到一个办法: 在 ...
- Linux Mint下FireFox安装Adobe Flash Player
最近在为自己的家里一台很老的机子(由于微软不再支持windows,windows10什么的不是这个老机子可以带的起来的233)选择一个合适的linux系统安装.看来看去,最终选择了排行很靠前,感觉也不 ...
- axios简单介绍
axios的配置,get,post,axiso的同步问题解决 一.缘由 vue-resoure不更新维护,vue团队建议使用axios. 二.axios安装 1.利用npm安装npm install ...
- mouseover和mouseenter闪烁的问题
span标签绑定mouseover/mouseout事件,显示/隐藏一个信息框div 该div下没有任何子元素 悬停上去一直闪烁,改成mouseenter也没用. 照成的原因是:悬停上去信息框div盖 ...
- openerp学习笔记 数据合法性约束(对象约束+数据库约束)
#检测同一时间段内是否存在相同的请假单,False 是存在,不允许创建 def _check_date(self, cr, uid, ids): for rec in self.b ...