前注:本文不是讲解Java类库的Hashtable实现原理,而是根据计算机哈希表原理自己实现的一个Hashtable。

HashTable内部是用数组存放一个(Key-Value pair)键值对的引用,其原理是根据Key的hashCode来计算出数组下标。因为存放位置是直接计算出来,不需要遍历数据结构,这使得hash table具有快速增删查改的优势。下面介绍HashTable的实现步骤:

  • 取得Key的hashCode。

  通过Eclipse等工具可以轻松的复写Object的hashCode方法,生成的hashCode是不会有重复值的。

  • 将hashCode与地址映射(压缩地址):

  但是,Hashtable内部是用一个数组来存储Key-Value对的,数组容量有限,本文中设置数组容量为10。那么现在的问题就是如何将hashCode和数组地址相对应?一个简单的方法就是对hashCode取模运算(hashCode%10)。这样就可以将hashCode与数组地址做映射(多对一)。同时注意,hashCode可能为负数,而数组的下标不能为负数,所以在映射的时候需要处理一下。

 int hashCode =  Math.abs(key.hashCode())% this.maxSize;
  • 解决hashCode重复问题:

上文已经说过,数组容量为10,当我们在将hashCode映射为数组下标的时候,肯定会遇到有重复的情况。比如hashCode为21和31,分别对他们取模运算,结果都是1,也就是说这两个hashCode对应数组的下标都是1.那么第一个元素添加上去后,再添加第二个元素,则新元素会覆盖之前的元素。这时,如果我们想后面添加的重复地址元素也能添加上去,只能将其放在其它位置。这时,我们可以将新元素放在改地址的下一位,如果下一位已经有元素,那么就继续往后找,直到找到空位为止(其实这个过程有些边界条件需要考虑,比如找到数组末尾后应跳到数组开头继续找。以及数组已经满了,找遍数组都找不到合适的位置,就应该提示该数组已满,不能插入)。

现在既然解决了上面的问题,也就是说每个元素都能在数组中找到合适的位置(除非数组已满)。那么可以根据这个算法实现数组的增删查改。下面是Hashtable的实现代码:

 package org.lyk.impl;

 public class HashTable<K, V>
{
/**
* Key-Value pair 存放键值对
* @author liuyuank
*
*/
private class KeyValue
{
K key;
V value; private 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 Object[] table;
private int maxSize = 10;
private int currentAmmount = 0; public HashTable()
{
this.table = new Object[this.maxSize];
} public HashTable(int maxSize) throws Exception
{
if (0 == maxSize || maxSize < 0 || maxSize > 100)
{
throw new Exception("table容量非法!");
} this.maxSize = maxSize;
this.table = new Info[maxSize];
} /**
* 增加一个键值对
* @param key
* @param value
*/
public void add(K key, V value)
{
//将hashCode映射到数组下标
int hashCode = Math.abs(key.hashCode())% this.maxSize; //将元素插入到数组中,如果该位置已经被占用,则循环查找下一个位置,直到找到合适的位置,或发现数组已满,退出循环
while (this.table[hashCode] != null
&& (this.currentAmmount < this.maxSize))
{
hashCode++;
hashCode = hashCode % this.maxSize;
} if (this.currentAmmount == this.maxSize)
{
//数组已满
System.out.println("Hash table 已满");
} else
{
//找到合适位置
this.table[hashCode] = new KeyValue(key, value);
this.currentAmmount++;
}
} /**
* 与add方法同样的算法,根据key值找到数组中元素,然后将改元素设置为null
* @param key
* @return
*/
public boolean remove(K key)
{
int hashCode = Math.abs(key.hashCode()) % this.maxSize;
int count = 0;
while (this.table[hashCode] != null && count < this.maxSize)
{
if (((KeyValue) this.table[hashCode]).getKey().equals(key))
{
this.table[hashCode] = null;
return true;
}
count++;
hashCode++;
hashCode = hashCode%this.maxSize;
} return false;
} public V get(K key)
{
int hashCode = Math.abs(key.hashCode()) % this.maxSize;
int count = 0;
while (this.table[hashCode] != null && count < this.maxSize)
{
if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
return ((KeyValue) this.table[hashCode]).getValue(); hashCode++;
count++;
hashCode = hashCode%this.maxSize;
}
return null;
} public boolean contains(K key)
{
if (this.get(key) != null)
{
return true;
} else
{
return false;
}
} public void replace(K key, V value)
{
KeyValue kv = this.find(key);
if(kv != null)
{
kv.setValue(value);
}
} private KeyValue find(K key)
{
int hashCode = Math.abs(key.hashCode()) % this.maxSize;
int count = 0;
while (this.table[hashCode] != null && count < this.maxSize)
{
if (key.equals(((KeyValue)this.table[hashCode]).getKey()))
return ((KeyValue) this.table[hashCode]); hashCode++;
count++;
hashCode = hashCode%this.maxSize;
}
return null;
}
}

HashTable实现

package org.lyk.impl;

import java.math.BigInteger;

public class Info
{
private String name;
private String address;
private Integer age; public Info(String name, String address, Integer age)
{
super();
this.name = name;
this.address = address;
this.age = age;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
} // @Override
// public int hashCode()
// {
// final int prime = 27;
// int result = 1;
// result = prime*result + (this.name == null ? 0:this.name.hashCode());
// result = prime*result + (this.address == null ? 0:this.address.hashCode());
// result = prime*result + (this.age == null ? 0 : this.age.hashCode());
// return result;
// } @Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Info other = (Info) obj;
if (address == null)
{
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (age == null)
{
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null)
{
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAddress()
{
return address;
}
public void setAddress(String address)
{
this.address = address;
}
public Integer getAge()
{
return age;
}
public void setAge(Integer age)
{
this.age = age;
}
@Override
public String toString()
{
return "Info [name=" + name + ", address=" + address + ", age=" + age
+ "]";
} }

Value实现

测试代码:String为Key Info为Value

package org.lyk.main;

import org.lyk.impl.BiTree;
import org.lyk.impl.HashTable;
import org.lyk.impl.Info; public class Main
{
public static void main(String[] args)
{
HashTable<String, Info> ht = new HashTable<>();
for(int i =0; i <15;i++)
{
Info info = new Info("sheldon" + i, "address" + i , i);
//System.out.println("hashCode in main:" + info.getName().hashCode());
ht.add(info.getName(), info);
} String key = "sheldon3";
System.out.println(ht.contains(key));
ht.replace(key, new Info("谢耳朵","美国洛杉矶", 999));
System.out.println(ht.contains(key));
System.out.println(ht.get(key));
System.out.println("///~ main done");
} }

开放地址法实现HashTable的更多相关文章

  1. 面试准备 - HashTable 的C#实现 开放地址法

    Hashtable是很经常在面试中遇到的数据结构,因为他的O(1)操作时间和O(n)空间 之所以自己写一份是因为: 加深对于hashtable的理解 某些公司面试的时候需要coding....... ...

  2. Hash冲突的线性探测开放地址法

    在实际应用中,无论如何构造哈希函数,冲突是无法完全避免的. 开放地址法 这个方法的基本思想是:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止.这个过程可用下式描述:  ...

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

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

  4. 开放地址法散列表ADT

    数据结构定义如下: typedef unsigned int Index; typedef Index Position; struct HashTbl; typedef struct HashTbl ...

  5. 链地址法实现HashMap

    前注:本文介绍的HashMap并非Java类库的实现.而是根据哈希表知识的一个实现. 上文介绍了开放地址法实现HashTable,它的缺点是对hashCode映射为地址后如果出现重复地址,则会占用其他 ...

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

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

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

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

  8. Python与数据结构[4] -> 散列表[2] -> 开放定址法与再散列的 Python 实现

     开放定址散列法和再散列 目录 开放定址法 再散列 代码实现 1 开放定址散列法 前面利用分离链接法解决了散列表插入冲突的问题,而除了分离链接法外,还可以使用开放定址法来解决散列表的冲突问题. 开放定 ...

  9. 开放定址法——线性探测(Linear Probing)

    之前我们所采用的那种方法,也被称之为封闭定址法.每个桶单元里存的都是那些与这个桶地址比如K相冲突的词条.也就是说每个词条应该属于哪个桶所对应的列表,都是在事先已经注定的.经过一个确定的哈希函数,这些绿 ...

随机推荐

  1. Thrift编译与验证 - python

    1 编译(保留了C和python语言,简化编译): # ./configure --without-java --without-cpp --without-php --without-erlang ...

  2. JQuery Cross Domain

    frontend: first :add $.support.cors=true; in front of the Ajax code. seconde: add the crossDomain:tr ...

  3. WinForm多线程学习文档

    基础篇 怎样创建一个线程 受托管的线程与 Windows线程 前台线程与后台线程 名为BeginXXX和EndXXX的方法是做什么用的 异步和多线程有什么关联 WinForm多线程编程篇 我的多线程W ...

  4. debug实战:COM组件GetToSTA导致高内存+GC被阻塞

    最近花了好几周解决一个WPF高内存的问题,问题的表象是内存不断增加.未被回收,根源是GC的FinalizeThread被阻塞,导致整个GC挂掉.从以下几步来分析这个问题: 1.用ANTS Memory ...

  5. Python开发入门与实战12-业务逻辑层

    12. Biz业务层 前面的章节我们把大量的业务函数都放在了views.py里,按照目前这一的写法,当我们编写的系统复杂较高时,我们的views.py将会越来越复杂,大量的业务函数包含其中使其成为一个 ...

  6. The Layout Process on Mac OSX and iOS

    First we will recap the steps it takes to bring views on screen with Auto Layout enabled. When you’r ...

  7. (转)PhoneGap开发环境搭建

    (原)http://www.cnblogs.com/Random/archive/2011/12/28/2305398.html PhoneGap开发环境搭建   项目中要用PhoneGap开发,了解 ...

  8. MySQL起航

    以前学php的时候用过MySQL,但是都没有认真地学习,只会在php代码中用几条极其简单SQL语句,以为MySQL就这么点用法,当时还在嘲笑学长们为什么会觉得MySQL难学,真是太尴尬了.好在开了数据 ...

  9. 搜索栏会消失 uisearchbar 狂点消失的问题解决

    经过反复试验和错误很多,我发现当searchdisplaycontroller结束搜索,搜索栏会消失,所以我重新插入到搜索栏表头和它为我工作. - (void)searchDisplayControl ...

  10. webStorm破解说明

    在idea里转一个 -> 注册时选择License server,填http://idea.lanyus.com