再哈希法:
为了消除原始聚集和二次聚集,可以使用另外一个方法:再哈希法,二次聚集产生的原因是,二次探测的算法产生的探测序列步长总是固定的:1,4,9,16…
x现在需要的一种方法是产生一种依赖关键字的探测序列,而不是每个关键字都一样。那么,不同的关键字即使映射到相同的数组下标,也可以使用不同的探测序列。
方法是把关键字用不同的哈希函数再做一遍哈希花,用这个结果作为步长,对指定的关键字,步长在整个探测中是不变的,不过不同的关键字使用不同的步长。
经验说明,第二个哈希函数必须具备以下特点:
和第一个哈希函数不同
不能输出0.
比如下面的哈希函数可以工作得很好:
stepSize = constant * (key % constant)
其中,constant是质数,且小于数组容量。
package com.hash;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.xml.crypto.Data;
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; //for deleted items
//.....................
public HashTable(int size)
{
arraySize = size;
hashArray =new DataItem[arraySize];
nonItem = new DataItem(-1); //deleted item key is -1
}
//................
public void displayTable()
{
System.out.println("Table:");
for (int i = 0; i < arraySize; i++)
{
if(hashArray[i] != null)
System.out.println(hashArray[i].getKey()+"");
else
System.out.println("");
}
System.out.println("");
}
//.............................
public int hashFunc1(int key)
{
return key % arraySize; //哈希函数
}
/*
* 要满足两个条件
* 和第一个哈希函数不同
* 不不能是0
*/
public int hashFunc2(int key)
{
return 5* key % 5;
}
//..........................
public void insert(DataItem item)
//假设哈希表没有
{
int key = item.getKey();
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];
//用特殊的数据项nonItem 覆盖原来的数据,这个变量事先定义为-1
hashArray[hashVal] = nonItem;
return temp;
}
hashVal += stepSize;
hashVal %= arraySize;
}
return null;
}
/*
* find()方法首先调用hashFunc()方法把待查找关键字转换成数组下标hashVal。
* hashFunc()方法把%操作符应用于查找关键字和数组容量。
* 接着,在while循环中,find()方法检查这个下标所指单元是否为空(null) 。如果不为空,
* 他会检查这个数据项是否包含待检查关键字,如果包含,find()方法返回这个数据项
* 如果不包含,find()递增hashVal,并且回到while循环的开始,检查下一个单元是否被占用。
*/
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;
}
//...............................
}
class HashDoubleApp
{
public static void main(String[] args) throws Exception
{
int aKey;
DataItem aDataItem;
int size,n;
System.out.print("Enter size of hash table:");
size = getInt();
System.out.print("Enetr initial number of items:");
n=getInt();
HashTable theHashTable = new HashTable(size);
for (int i = 0; i < n; i++)
{
aKey = (int)(java.lang.Math.random() * 2*size);
aDataItem =new DataItem(aKey);
theHashTable.insert(aDataItem);
}
while(true)
{
System.out.print("Enter firdt 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(aDataItem);
break;
case 'd':
System.out.print("Enter key value to delete:");
aKey = getInt();
theHashTable.delete(aKey);
break;
case 'f':
System.out.println("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 enery\n");
}
}
}
//.......................
public static String getString() throws Exception
{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
//.........................
public static char getChar() throws Exception
{
String s= getString();
return s.charAt(0);
}
//...............
public static int getInt() throws Exception
{
String s= getString();
return Integer.parseInt(s);
}
}