链地址法实现HashMap
前注:本文介绍的HashMap并非Java类库的实现。而是根据哈希表知识的一个实现。
上文介绍了开放地址法实现HashTable,它的缺点是对hashCode映射为地址后如果出现重复地址,则会占用其他元素的位置。这样HashTable存储容量有限,而且不便于算法理解。本文介绍链地址法实现HashMap。
链地址法内部仍然有一个数组,但区别与开放地址法,该数组存储的是一个链表的引用。当根据hashCode计算出数组下表后,对元素的增删查改都是在该数组元素所指向的链表上完成的。这就解决了hashCode重复的问题。因为,当hashCode重复,多个元素对应同一个地址,但元素实际存储的位置在数组对应的链表上。所以相同hashCode的不同元素可以存储在同一位置。
下面是代码实现:
package org.lyk.interfaces; public interface IMap<K,V>
{
/**
* 根据key值增加一个value,如果key重复,则新元素替换旧元素
* @param key
* @param value
*/
public void put(K key, V value);
/**
* 根据key值移除value
* @param key
* @return
*/
public boolean remove(K key);
public V get(K key);
public boolean contains(K key);
public void replace(K key, V value); }
IMap
package org.lyk.impl; import java.util.ArrayList;
import org.lyk.interfaces.IMap; public class HashMap<K,V> implements IMap<K, V>
{
private class KeyValue
{
private K key;
private V value; public KeyValue(K key, V value)
{
this.key = key;
this.value = value;
} public K getKey()
{
return key;
}
public void setKey(K key)
{
this.key = key;
}
public V getValue()
{
return value;
}
public void setValue(V value)
{
this.value = value;
} }
private int maxSize = 10;
private Object[] table; public HashMap()
{
this.table = new Object[this.maxSize];
for(int i = 0; i < this.maxSize; i++)
{
this.table[i] = new java.util.ArrayList<KeyValue>();
}
} @Override
public void put(K key, V value)
{
int index = this.getIndex(key);
KeyValue kv = this.find(key);
if(kv == null)
{
((java.util.List<KeyValue>)this.table[index]).add(new KeyValue(key, value));
}
else
{
kv.setValue(value);
}
} @Override
public boolean remove(K key)
{
int index = this.getIndex(key);
java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index];
int listIndex = -1;
for(KeyValue kv : kvs)
{
if(kv.key.equals(key))
{
listIndex = kvs.indexOf(kv);
}
}
if(listIndex != -1)
{
kvs.remove(listIndex);
return true;
}
return false;
} @Override
public V get(K key)
{
KeyValue kv= this.find(key);
if(kv != null)
return kv.getValue();
else
return null;
} @Override
public boolean contains(K key)
{
if(this.get(key) != null)
return true;
else
return false;
} @Override
public void replace(K key, V value)
{
KeyValue kv = this.find(key);
if(kv != null)
{
kv.setValue(value); }
} private int getIndex(K key)
{
return Math.abs(key.hashCode())%this.maxSize;
} private KeyValue find(K key)
{
int index = this.getIndex(key);
java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index];
for(KeyValue kv : kvs)
{
if(kv.key.equals(key))
{
return kv;
}
} return null;
}
}
HashMap
链地址法实现HashMap的更多相关文章
- java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...
- POJ 3007 Organize Your Train part II(哈希链地址法)
http://poj.org/problem?id=3007 题意 :给你一个字符串,让你无论从什么地方分割,把这个字符串分成两部分s1和s2,然后再求出s3和s4,让你进行组合,看能出来多少种不同的 ...
- C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法、再哈希法、链地址法、建立一个公共溢出区等
C# Dictionary源码剖析 参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/ ...
- PKU 2002 Squares(二维点哈希+平方求余法+链地址法)
题目大意:原题链接 给定平面上的N个点,求出这些点一共可以构成多少个正方形. 解题思路: 若正方形为ABCD,A坐标为(x1, y1),B坐标为(x2, y2),则很容易可以推出C和D的坐标.对于特定 ...
- SWUST OJ 1012哈希表(链地址法处理冲突)
哈希表(链地址法处理冲突) 1000(ms) 10000(kb) 2676 / 6911 采用除留余数法(H(key)=key %n)建立长度为n的哈希表,处理冲突用链地址法.建立链表的时候采用尾插法 ...
- Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不 ...
- 链地址法查找成功与不成功的平均查找长度ASL
晚上,好像是深夜了,突然写到这类题时遇到的疑惑,恰恰这个真题只让计算成功的ASL,但我想学一下不成功的计算,只能自己来解决了,翻了李春葆和严蔚敏的教材没有找到相关链地址法的计算,于是大致翻到两篇不错的 ...
- poj3349(哈希+链地址法)
给出N个六边形的6个边长,问其中是否有完全相同的两个六边形,完全相同包括边的长度和位置都要相同.边给出的顺序是逆时针或者顺时针的. 给每个6边形一个哈希值,方法是对6条边长度的平方和取模 #inclu ...
- 哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现
#include<iostream>#include<iomanip>using namespace std; typedef struct Node{ int data; s ...
随机推荐
- Zabbix点滴
[ZABBIX需试验的项] 1. 手工设置ITEM, 采用descr为依据值,用SNMP取流量 2. 通过aggregate item类型,设置取虚拟机数量的值(描绘出虚拟机的增长与下降曲线) [20 ...
- buaaoj230——next_permutation的应用
题目地址 简单的全排列输出,借用stl中的next_permutation就非常简单了. 关于next_permutation:(备忘,来源网络) /*这是一个求一个排序的下一个排列的函数,可以遍历全 ...
- Node.js 事件
Node.js 事件 Node.js 所有的异步I/O 操作在完成时都会发送一个事件到事件队列. Node.js里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时分发一个事件, ...
- Linux学习 : 裸板调试 之 配置使用NAND FLASH
关于NAND FLASH的结构是以页为单位写,以块为单位来擦除: 1Gb 为大页 page=2048Kb BLOCK=128K 512Mb 为小页 page=512byte ...
- javascript高级教程:如何优化javascript代码性能
在web前端开发中,为实现一些动态效果,减小页面大小,我们一般都会使用JavaScript技术来进行相关设置.但是初学者在编写JavaScript代码的时候,往往都是比较低质的代码,那如何才能提高Ja ...
- C#实现右下角弹出窗口效果
/// <summary> /// 窗体动画函数 注意:要引用System.Runtime.InteropServices; /// </summary> /// <pa ...
- Android Studio Tips and Tricks
Android Studio Delete Module 1.选中Module右击,选择 Open Module Settings,打开Project Structure 窗空.(或者选中Module ...
- 【C++ STL编程】queue小例子
STL是标准化组件,现在已经是C++的一部分,因此不用额外安装什么. #include <queue> #include <iostream> using namespace ...
- JSP应用程序(自定义错误页面)
一.编写 1.index.jsp <%@page contentType="text/html" pageEncoding="UTF-8"%> &l ...
- Javascript 事件对象(二)event事件
Event事件: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" ...