哈希表中,一串连续的已填充单元叫做填充序列。增加越来越多的数据项时,填充序列变的越来越长,这叫做聚集。
为了消除原始聚集和二次聚集,可以使用另外的一个方法:再哈希法:一种依赖关键字的探测序列,而不是每个关键字都一样,那么,不同的关键字即使映射到相同的数组下标,也可以使用不同的探测序列。
方法是把关键字用不同的哈希函数再做一次哈希化,用这个结果作步长,对指定的关键字,步长在整个探测中是不变的,不同的关键字使用不同的步长。
数组实现的哈希表,开放地址法之再哈希法:
![](http://dl.iteye.com/upload/attachment/0077/6527/c2c1bb99-e7da-3916-887f-f93f4a340f1e.gif)
![](http://dl.iteye.com/upload/attachment/0077/6530/5adaf1f1-2fc9-3675-932c-515c9080da92.gif)
为了消除原始聚集和二次聚集,可以使用另外的一个方法:再哈希法:一种依赖关键字的探测序列,而不是每个关键字都一样,那么,不同的关键字即使映射到相同的数组下标,也可以使用不同的探测序列。
方法是把关键字用不同的哈希函数再做一次哈希化,用这个结果作步长,对指定的关键字,步长在整个探测中是不变的,不同的关键字使用不同的步长。
![](http://dl.iteye.com/upload/attachment/0077/6532/1ffc90d5-3ce4-3309-b0dd-ed8a6baf219e.gif)
数组实现的哈希表,开放地址法之再哈希法:
- import java.io.*;
- class DataItem {//数据项
- private int iData; // 数据项的关键字
- public DataItem(int ii)
- { iData = ii; }
- public int getKey()
- { return iData; }
- }
- class HashTable{//数组实现的哈希表,开放地址法之再哈希法
- private DataItem[] hashArray; //存数据的数组
- private int arraySize;
- private DataItem nonItem; //已删除标志
- HashTable(int size) {//哈希表构造函数
- arraySize = size;
- hashArray = new DataItem[arraySize];
- nonItem = new DataItem(-1);
- }
- public void displayTable()//输出哈希表
- {
- System.out.print("Table: ");
- for(int j=0; j<arraySize; j++)
- {
- if(hashArray[j] != null)
- System.out.print(hashArray[j].getKey()+ " ");
- else
- System.out.print("** ");
- }
- System.out.println("");
- }
- //哈希函数1
- public int hashFunc1(int key){
- return key % arraySize;
- }
- //哈希函数2,不同于哈希函数1,用于再哈希。
- public int hashFunc2(int key){
- // array size must be relatively prime to 5, 4, 3, and 2
- return 5 - key % 5;
- }
- //哈希表中插入数据
- public void insert(int key, DataItem item){
- int hashVal = hashFunc1(key); //求关键字的哈希值
- int stepSize = hashFunc2(key); // 再探测步长的大小
- while(hashArray[hashVal] != null && hashArray[hashVal].getKey() != -1) {
- hashVal += stepSize; //单元被占用,再探测
- hashVal %= arraySize;
- }
- hashArray[hashVal] = item;
- }
- //在哈希表中删除
- public DataItem delete(int key) {
- int hashVal = hashFunc1(key);
- int stepSize = hashFunc2(key);
- while(hashArray[hashVal] != null){//直到一个空单元出现
- if(hashArray[hashVal].getKey() == key){
- DataItem temp = hashArray[hashVal];
- hashArray[hashVal] = nonItem; //作删除标记
- return temp;
- }
- hashVal += stepSize; //再探测
- hashVal %= arraySize;
- }
- return null;
- }
- //在哈希表中搜索
- public DataItem find(int key){
- int hashVal = hashFunc1(key);
- int stepSize = hashFunc2(key);
- while(hashArray[hashVal] != null) {
- if(hashArray[hashVal].getKey() == key)
- return hashArray[hashVal];
- hashVal += stepSize;
- hashVal %= arraySize;
- }
- return null;
- }
- }
- public class HashDoubleApp{
- public static void main(String[] args) throws IOException{
- int aKey;
- DataItem aDataItem;
- int size, n;
- System.out.print("Enter size of hash table: ");
- size = getInt();
- System.out.print("Enter initial number of items: ");
- n = getInt();
- HashTable theHashTable = new HashTable(size);
- for(int j=0; j<n; j++){
- aKey = (int)(java.lang.Math.random() * 2 * size);
- aDataItem = new DataItem(aKey);
- theHashTable.insert(aKey, aDataItem);
- }
- while(true){
- System.out.print("Enter first letter of ");
- System.out.print("show, insert, delete, or find: ");
- char choice = getChar();
- switch(choice)
- {
- case 's':
- theHashTable.displayTable();
- break;
- case 'i':
- System.out.print("Enter key value to insert: ");
- aKey = getInt();
- aDataItem = new DataItem(aKey);
- theHashTable.insert(aKey, aDataItem);
- break;
- case 'd':
- System.out.print("Enter key value to delete: ");
- aKey = getInt();
- theHashTable.delete(aKey);
- break;
- case 'f':
- System.out.print("Enter key value to find: ");
- aKey = getInt();
- aDataItem = theHashTable.find(aKey);
- if(aDataItem != null)
- System.out.println("Found " + aKey);
- else
- System.out.println("Could not find " + aKey);
- break;
- default:
- System.out.print("Invalid entry\n");
- }
- }
- }
- public static String getString() throws IOException
- {
- InputStreamReader isr = new InputStreamReader(System.in);
- BufferedReader br = new BufferedReader(isr);
- String s = br.readLine();
- return s;
- }
- public static char getChar() throws IOException
- {
- String s = getString();
- return s.charAt(0);
- }
- public static int getInt() throws IOException
- {
- String s = getString();
- return Integer.parseInt(s);
- }
- }
import java.io.*;
class DataItem {//数据项
private int iData; // 数据项的关键字
public DataItem(int ii)
{ iData = ii; }
public int getKey()
{ return iData; }
}
class HashTable{//数组实现的哈希表,开放地址法之再哈希法
private DataItem[] hashArray; //存数据的数组
private int arraySize;
private DataItem nonItem; //已删除标志
HashTable(int size) {//哈希表构造函数
arraySize = size;
hashArray = new DataItem[arraySize];
nonItem = new DataItem(-1);
}
public void displayTable()//输出哈希表
{
System.out.print("Table: ");
for(int j=0; j<arraySize; j++)
{
if(hashArray[j] != null)
System.out.print(hashArray[j].getKey()+ " ");
else
System.out.print("** ");
}
System.out.println("");
}
//哈希函数1
public int hashFunc1(int key){
return key % arraySize;
}
//哈希函数2,不同于哈希函数1,用于再哈希。
public int hashFunc2(int key){
// array size must be relatively prime to 5, 4, 3, and 2
return 5 - key % 5;
}
//哈希表中插入数据
public void insert(int key, DataItem item){
int hashVal = hashFunc1(key); //求关键字的哈希值
int stepSize = hashFunc2(key); // 再探测步长的大小
while(hashArray[hashVal] != null && hashArray[hashVal].getKey() != -1) {
hashVal += stepSize; //单元被占用,再探测
hashVal %= arraySize;
}
hashArray[hashVal] = item;
}
//在哈希表中删除
public DataItem delete(int key) {
int hashVal = hashFunc1(key);
int stepSize = hashFunc2(key);
while(hashArray[hashVal] != null){//直到一个空单元出现
if(hashArray[hashVal].getKey() == key){
DataItem temp = hashArray[hashVal];
hashArray[hashVal] = nonItem; //作删除标记
return temp;
}
hashVal += stepSize; //再探测
hashVal %= arraySize;
}
return null;
}
//在哈希表中搜索
public DataItem find(int key){
int hashVal = hashFunc1(key);
int stepSize = hashFunc2(key);
while(hashArray[hashVal] != null) {
if(hashArray[hashVal].getKey() == key)
return hashArray[hashVal];
hashVal += stepSize;
hashVal %= arraySize;
}
return null;
}
}
public class HashDoubleApp{
public static void main(String[] args) throws IOException{
int aKey;
DataItem aDataItem;
int size, n;
System.out.print("Enter size of hash table: ");
size = getInt();
System.out.print("Enter initial number of items: ");
n = getInt();
HashTable theHashTable = new HashTable(size);
for(int j=0; j<n; j++){
aKey = (int)(java.lang.Math.random() * 2 * size);
aDataItem = new DataItem(aKey);
theHashTable.insert(aKey, aDataItem);
}
while(true){
System.out.print("Enter first letter of ");
System.out.print("show, insert, delete, or find: ");
char choice = getChar();
switch(choice)
{
case 's':
theHashTable.displayTable();
break;
case 'i':
System.out.print("Enter key value to insert: ");
aKey = getInt();
aDataItem = new DataItem(aKey);
theHashTable.insert(aKey, aDataItem);
break;
case 'd':
System.out.print("Enter key value to delete: ");
aKey = getInt();
theHashTable.delete(aKey);
break;
case 'f':
System.out.print("Enter key value to find: ");
aKey = getInt();
aDataItem = theHashTable.find(aKey);
if(aDataItem != null)
System.out.println("Found " + aKey);
else
System.out.println("Could not find " + aKey);
break;
default:
System.out.print("Invalid entry\n");
}
}
}
public static String getString() throws IOException
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
public static char getChar() throws IOException
{
String s = getString();
return s.charAt(0);
}
public static int getInt() throws IOException
{
String s = getString();
return Integer.parseInt(s);
}
}