前注:本文介绍的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的更多相关文章

  1. java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...

  2. POJ 3007 Organize Your Train part II(哈希链地址法)

    http://poj.org/problem?id=3007 题意 :给你一个字符串,让你无论从什么地方分割,把这个字符串分成两部分s1和s2,然后再求出s3和s4,让你进行组合,看能出来多少种不同的 ...

  3. C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法、再哈希法、链地址法、建立一个公共溢出区等

    C# Dictionary源码剖析 参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/ ...

  4. PKU 2002 Squares(二维点哈希+平方求余法+链地址法)

    题目大意:原题链接 给定平面上的N个点,求出这些点一共可以构成多少个正方形. 解题思路: 若正方形为ABCD,A坐标为(x1, y1),B坐标为(x2, y2),则很容易可以推出C和D的坐标.对于特定 ...

  5. SWUST OJ 1012哈希表(链地址法处理冲突)

    哈希表(链地址法处理冲突) 1000(ms) 10000(kb) 2676 / 6911 采用除留余数法(H(key)=key %n)建立长度为n的哈希表,处理冲突用链地址法.建立链表的时候采用尾插法 ...

  6. Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区

    最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不 ...

  7. 链地址法查找成功与不成功的平均查找长度ASL

    晚上,好像是深夜了,突然写到这类题时遇到的疑惑,恰恰这个真题只让计算成功的ASL,但我想学一下不成功的计算,只能自己来解决了,翻了李春葆和严蔚敏的教材没有找到相关链地址法的计算,于是大致翻到两篇不错的 ...

  8. poj3349(哈希+链地址法)

    给出N个六边形的6个边长,问其中是否有完全相同的两个六边形,完全相同包括边的长度和位置都要相同.边给出的顺序是逆时针或者顺时针的. 给每个6边形一个哈希值,方法是对6条边长度的平方和取模 #inclu ...

  9. 哈希查找解决地址冲突的两种最常见方法(线性探测再散列,链地址法)C++实现

    #include<iostream>#include<iomanip>using namespace std; typedef struct Node{ int data; s ...

随机推荐

  1. yarn 0.9.0 build spark

    1. 下载scala并安装.版本为2.10.3.设置SCALA_HOME和PATH环境变量 2. 下载SPARK 0.9.0源代码并解压到/root/Downloads/spark-0.9.0-inc ...

  2. 【转】 linux之sed用法

    sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特定工作,下面先了解一下sed的用法sed命令行格式为:         sed ...

  3. 《大象-Think In UML》读书笔记1

    大音希声,大象希行. 什么是面向过程?什么是面向对象? 面向过程归纳为结构化程序设计.DFD图.ER模型.UC矩阵等,而面向对象则被归纳为继承.封装.多态.复用等具体的技术.事实上,上述的所有技术都只 ...

  4. What is Requirement ?

    The IEEE 610 standard defines a requirement as: (1). a condition or capability needed by a user to s ...

  5. 小议安卓定位伪造-实战足不出户畅玩Pokemon Go

    本文旨在技术探讨故本文不提供工具,正常玩家请勿模仿,游戏中虚拟位置有封号风险 0x00 安卓定位方式归类 要伪造定位首先要摸清定位到底是如何实现的,首先从广义上来区分安卓的定位方式实际上就gps和ne ...

  6. BZOJ 1500 Splay 全操作

    好久没写splay了,写一发(写了一节课,调了一节课) #include <iostream> #include <cstring> #include <cstdio&g ...

  7. 复健小CM

    系统 : Windows xp 程序 : Keygenme # 2 程序下载地址 :http://pan.baidu.com/s/1qYIk2HQ 要求 : 注册机编写 使用工具 : OD 可在“PE ...

  8. Windows和Unix下的编码问题

    今天测试shell脚本时,执行报错: ./report.sh: /tmp/tmp.E8ekx6r5Qq/report.sh: /bin/bash^M: bad interpreter: No such ...

  9. PL/SQL工具连接ORALCE数据库的方法

    http://www.cnblogs.com/dongzhiquan/archive/2011/11/21/2257629.html 1.利用ORACLE NET MANAGER工具 1)打开 ORA ...

  10. python数据结构与算法——字典树

    class TrieTree(): def __init__(self): self.root = {} def addNode(self,str): # 树中每个结点(除根节点),包含到该结点的单词 ...