简易实现HashMap核心代码
实现效果:模拟HashMap
的存入和取出
HashMap底层存储的数据结构
实现步骤
1).创建SimpleHashMap
类(模拟HashMap
)
2).构建SimpleHashMap类
的内部类HashNode
(为HashMap的一个桶)
3).定义成员变量ArrayList<HashNode> bucketArray
为桶数组
4).定义成员变量int numBuckets
记录桶的个数
5).定义成员变量int size
记录HashMap中有效元素个数
6).成员方法…
一:定义链表中节点类型
class HashNode{
private Object key;
private Object value;
private HashNode next;
public HashNode(Object key, Object value) {
this.key = key;
this.value = value;
}
}
二:定义散列表(桶数组)
private ArrayList<HashNode> bucketArray;
三:定义桶的个数
private int numBuckets;
四:定义size记录有效元素个数
private int size;
五:通过构造方法对散列表初始化
public SimpleHashMap(int nunBuckets) {
this.numBuckets=nunBuckets;
bucketArray=new ArrayList<>();
for (int i = 0; i <nunBuckets; i++) {
bucketArray.add(null);
}
}
六:定义一个散裂函数:用于计算hash值
public int hash(Object key) {
int hashCode=key.hashCode();
int index=hashCode%numBuckets;
return index;
}
七:核心方法一:定义数据添加函数
public void put(Object key,Object value) {
// 1.基于key获取其散裂值(下标值)
int index=hash(key);
// 2.获取散裂表中对桶对象(链表节点)
HashNode head=bucketArray.get(index);
// 3.检测链表中是否有key相同对元素,key相同值覆盖
while(head!=null) {
// key 值相同值覆盖
if(head.key.equals(key)) {
head.value=value;
return;
}
head=head.next;
}
// 4.添加新的key/value到桶中
// 4.1获取指定下标对应的桶对象的head节点
head=bucketArray.get(index);
// 4.2创建新的node节点
HashNode newNode=new HashNode(key, value);
// 4.3将新节点设置为当前桶中的头节点
newNode.next=head;
// 4.4将指定index位置的头节点设置为新的头节点
bucketArray.set(index, newNode);
// 4.5执行size++操作
size++;
// 5.对散列表进行扩容设计 *** 0.8为加载因子
if((1.0*size)/numBuckets>=0.8) {
ArrayList<HashNode>temp=bucketArray;
numBuckets=numBuckets*2; // 将桶个数设置为原有桶个数的2倍
bucketArray=new ArrayList<>(); // 新的散列表
for (int i = 0; i < numBuckets; i++) {
bucketArray.add(null);
}
size=0;
// 将原有散列表中的数据拷贝到新的列表中
for (HashNode headNode : temp) {
while(headNode !=null) {
put(headNode.key,headNode.value);
headNode=headNode.next;
}
}
}
}
八:核心方法二:基于key删除指定元素value
public Object remove(Object key) {
// 1.对key进行散裂求值
int index=hash(key);
// 2.获取index对应对桶
HashNode head=bucketArray.get(index);
// 3.在桶寻找key对应对节点,然后进行删除操作
HashNode prev=null;
while(head!=null) {
if(head.key.equals(key)) {
break;
}
prev=head;
head=head.next;
}
if(head==null)
return null;
if(prev!=null) {
prev.next=head.next;
}else {
bucketArray.set(index, head.next);
}
size--;
return head.value;
}
九:核心方法三:根据key获取value值
public Object get(Object key) {
// 1.对key进行散裂求值
int index=hash(key);
// 2.获取index对应对桶
HashNode head=bucketArray.get(index);
// 3.获取key对应对value值
while(head!=null) {
if(head.key.equals(key)) {
return head.value;
}
head=head.next;
}
return null;
}
十:计算散列表中有效元素的方法
public int size() {
return size;
}
进行测试:
public static void main(String[] args) {
SimpleHashMap map=new SimpleHashMap(2);
map.put("this", 1);
map.put("coder", 2);
map.put("this", 3);
System.out.println(map.size);
System.out.println(map.get("this"));
System.out.println(map.get("coder"));
map.remove("this");
System.out.println(map.size);
System.out.println(map.get("this"));
}
散裂(Hash)基本面试分析:
!:如何对散裂(Hash)函数进行设计?
对与散裂函数对设计,一般要遵循如下几个元则:
· 对于给定的key,经过散裂计算,得到散列值应该是一个非负整数
·对于给定相同的key,经过同样的散列计算,一个得到的散列值
·对应不同的key,经过相同的散列计算,得到的散列值应尽量相同