1,实现思路

public class HashedDictionary<K, V> implements DictionaryInterface<K, V>,
Serializable {

定义HashedDictionary.java,作为Hash词典的实现,该词典实现了如下功能:

①向词典中添加元素 ,②根据查找键从词典中删除元素, ③从词典中获取某个查找键的值, ④实现了词典中查找键Key的迭代器和Value的迭代器

2,对于Map词典而言,由第一行代码知:它底层实质上是一个数组。

第三行代码中的locationUsed 用来记录哈希表中某个位置是否被使用。由于冲突处理的需要,当删除某个元素时,只是将该元素作为标记删除而不是真正删除该元素,那么该元素所占用的位置实质上是已经被使用了的。但是,关于这个变量,程序还是有问题的。

     private TableEntry<K, V>[] hashTable;
private int numberOfEntries;//hashTable元素个数
private int locationUsed;//记录hashTable 位置的使用
private static final int DEFAULT_SIZE = 101;// 哈希表的默认大小,素数
private static final double MAX_LOAD_FACTOR = 0.5;// 装载因子

3,构造函数,用来生成一个Hash词典实例,从第六行代码看出,它实质上是 new 一个TableEntry类型的数组,而这个数组就是用来存放<key,value>对的索引。TableEntry是HashedDictionary的一个内部类,正是由它来封装实际的<key,value>元素,而HashedDictionary的对象就代表一个词典,词典的基本操作就是操作TableEntry数组指向的每个<key,value>

     public HashedDictionary(int tableSize) {
/*
* 当用来构造哈希表的参数不是素数时,寻找与该参数最接近的下一个素数
*/
int primeSize = getNextPrime(tableSize);
hashTable = new TableEntry[primeSize];
numberOfEntries = 0;
locationUsed = 0;
}
 private class TableEntry<S, T> implements Serializable {
private S entryKey;
private T entryValue;
private boolean inTable;

4,再看看迭代器的实现

这两个内部分别用来实现Key的迭代器和Value的迭代器,只需要实现在Iterator接口中定义好的方法即可,然后在HashedDictionary.java中再定义两个函数用来获得KeyIterator类型和ValueIterator类型的迭代器即可。

private class KeyIterator implements Iterator<K>{
...... private class ValueIterator implements Iterator<V>{
public Iterator<K> getKeyIterator() {
return new KeyIterator();
}
public Iterator<V> getValueIterator() {
return new ValueIterator();
}

5,哈希函数是如何实现的

先通过hashCode方法获得查找键的散列码,再将散列码压缩到哈希表的表长范围内

     private int getHashIndex(K key){
//先获得散列码,再通过 %(求余运算) 将散列码压缩为索引
int hashIndex = key.hashCode() % hashTable.length;
if(hashIndex < 0)
hashIndex = hashIndex + hashTable.length;
return hashIndex;
}

6,在添加<key,value>元素时是如何处理冲突的?这里采用了开放定址之线性探测法处理冲突。

调用probe(index,key)来处理冲突.处理冲突的原理如下:

removedStateIndex 用来记录哈希表中“第一个已删除元素的索引”---因为采用线性探测处理冲突,比如说有4个元素 a,b,c,d 都映射到第4个索引位置,则a在第4号位置,b在第5号位置,c在第6号位置,d在第7号位置。现假设第5号和第6号元素都被删除了,那么removeStateIndex会标记第5号位置。这样做的原因是:当待插入的新元素被映射到第4号位置时,若后面所有元素的查找键与待插入元素的查找键不同,则将该新元素插入到第5号位置,而不是将它插入到后面的某个值为null的位置(当然,若没有被标记删除的元素,它将会插入到哈希表中第一个值为null的元素)

处理结果是:若找到了与待插入元素的查找键相同的元素,则返回该元素的索引位置,add方法将更新该索引位置处的值。

若没有找到与待插入元素的查找键相同的元素,则要么插入到removedStateIndex(值不为-1)标记的索引位置,要么插入到哈希表中第一个值为null的元素索引位置。

     public V add(K key, V value) {
V oldValue;
if(isFull())
rehash();
int index = getHashIndex(key);
index = probe(index, key);//线性探测
 private int probe(int index, K key){
boolean found = false;
int removedStateIndex = -1;
while(!found && (hashTable[index] != null)){
if(hashTable[index].isIn()){
if(key.equals(hashTable[index].getEntryKey()))
found = true;
else
index = (index + 1) % hashTable.length;
}
else
{//保存处于已删除状态的第一个位置的索引(查找过程中遇到了被标记删除的元素)
if(removedStateIndex == -1)
removedStateIndex = index;
index = (index + 1) % hashTable.length;//继承探测后面的元素的键是否与查找键相同
}
}//end while
if(found || (removedStateIndex == -1))
return index;
else
return removedStateIndex;
}

7,由于可能产生冲突,某个Key通过散列函数生成索引之后,该索引位置可能已经存放了其它元素,那它又是如何正确地通过getValue(K key)方法来正确取得key所对应的value?-----locate(index, key)函数的功能。

因为getValue方法根据Key获得的Value可能是某个被冲突的元素的值,而不是Key所对应的Value,因此需要继承向后比较Key。

     public V getValue(K key) {
V result = null;
int index = getHashIndex(key);//获得key对应的哈希索引
index = locate(index, key);//返回处理冲突后的最终的索引地址 if(index != -1)
result = hashTable[index].getEntryValue();
return result;
}
 private int locate(int index, K key){
boolean found = false;
//当找到一个hashTable中为null的元素,表示查找失败
while(!found && (hashTable[index] != null)){
//index 处 的key对应的value没有被标记删除且key 相同时
if(hashTable[index].isIn() && key.equals(hashTable[index].getEntryKey()))
found = true;
else
index = (index + 1) % hashTable.length;
}
int result = -1;
if(found)
result = index;
return result;
}

词典的实现(4)-使用Hash方式来实现词典的更多相关文章

  1. 魔咒词典 HDU - 1880 (字符串hash 单hash转int或者 双hash )

    哈利波特在魔法学校的必修课之一就是学习魔咒.据说魔法世界有100000种不同的魔咒,哈利很难全部记住,但是为了对抗强敌,他必须在危急时刻能够调用任何一个需要的魔咒,所以他需要你的帮助. 给你一部魔咒词 ...

  2. 词典(二) 哈希表(Hash table)

    散列表(hashtable)是一种高效的词典结构,可以在期望的常数时间内实现对词典的所有接口的操作.散列完全摒弃了关键码有序的条件,所以可以突破CBA式算法的复杂度界限. 散列表 逻辑上,有一系列可以 ...

  3. 利用百度词典API和Volley网络库开发的android词典应用

     关于百度词典API的说明,地址在这里:百度词典API介绍 关于android网络库Volley的介绍说明,地址在这里:Android网络通信库Volley 首先我们看下大体的界面布局!

  4. 词典的实现(1)--Map的底层实现

    1,词典是这样的一种数据结构:它能根据给定的键(索引值,key)来查找其对应的值(value)是否存在,在JAVA中主要由java.util.HashMap来完成该功能.如电话本就是词典的一个具体实例 ...

  5. HDU-魔咒词典(字符串hash)

    魔咒词典 TimeLimit: 8000/5000 MS (Java/Others)  MemoryLimit: 32768/32768 K (Java/Others) 64-bit integer ...

  6. HDU 1880 魔咒词典 (Hash)

    魔咒词典 Time Limit: 8000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  7. HanLP的自定义词典使用方式与注意事项介绍

    [环境]python 2.7 方法一:使用pyhanlp,具体方法如下: pip install pyhanlp  # 安装pyhanlp 进入python安装包路径,如 /usr/lib/pytho ...

  8. 在Hanlp词典手动添加未登录词的方式介绍

    在使用Hanlp词典进行分词的时候,会出现分词不准的情况,原因是内置词典中并没有收录当前这个词,也就是我们所说的未登录词,只要把这个词加入到内置词典中就可以解决类似问题,如何操作呢,下面我们来看一下: ...

  9. hdu 1880 魔咒词典(双hash)

    魔咒词典Time Limit: 8000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

随机推荐

  1. Oracle 控制文件管理

    控制文件是一个很小的二进制文件(10MB左右),含有数据库结构信息,包括数据文件和日志文件信息.控制文件在数据库创建时被自动创建,并在数据库发生物理变数时更新.控制文件被不断更新,在任何时候都要保证控 ...

  2. 文件系统的block 数据库中的block 以及内存中的page基础知识汇总(自己理解 可能有误)

    1. 操作系统文件系统中的的block 文件系统中的block 是文件系统最小的读写单元,在HDD的磁盘时代, 一般block的大小可能与磁盘的扇区大小一致为 512bytes 也因为这个原因MBR启 ...

  3. Delphi 2010 3513正式版破解

    Delphi 2010 3513正式 一.下载ISO文件右键迅雷下载 二.安装完成后,先运行一下程序,程序会弹出叫你注册对话框,逐步点击Cancel---->OK----->No----& ...

  4. matplotlib之scatter自动绘制散点

    # 使用matplotlib.pyplot.scatter绘制散点 import matplotlib.pyplot as plt from pylab import mpl # 设置默认字体,解决中 ...

  5. C# 之抽象类和抽象方法

    概述:abstract 关键字  抽象类不能被实例化,抽象方法不能有方法体,抽象类中的所有抽象方法必须在子类中重写(override ),一个抽象类可以同时包含抽象方法和非抽象方法. abstract ...

  6. python---random模块详解

    在python中用于生成随机数的模块是random,在使用前需要import, 下面看下它的用法. random.random random.random()用于生成一个0到1的随机符点数: 0 &l ...

  7. Django-website 程序案例系列-11 验证装饰器

    FBV装饰器: def auth(func): #装饰器函数 def inner(request, *args, **kwargs): v = request.COOKIES.get('usernam ...

  8. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  9. 自学Aruba6.2-控制器基本维护操作(web页面配置)

    点击返回:自学Aruba之路 自学Aruba6.2-控制器基本维护操作(web页面配置) 1 显示当前控制器版本 Dashboard---Controller中 2 升级Aruab os版本 Main ...

  10. numpy 从入门到遗忘

    不常用的函数总是遗忘,很是困扰啊.于是痛下时间,做一个系统的总结,纯原创,都是些实际项目中常用的函数和方法,当然还有一些这边也是没有记录的,因为我在实际数据处理过程中也没有遇到过(如字符串处理等等). ...