散列函数:除法映射 f(k)=k%D
解决溢出:线性开型寻址
线性开型寻址即是当发生冲突时,把元素存储到下一个可用的“桶”中。
初始化
散列表使用数组实现,将数组全部初始化为-1,-1代表当前“桶”为空。usedLen字段代表以使用的数组长度,bucketsLen字段代表数组的长度,因为经常使用数组的长度,所以我专门使用一个字段表示数组的长度。
private int[] buckets;
private int usedLen;
private int bucketsLen;
public OpenAddressingHash(int bucketsLen) {
this.bucketsLen = bucketsLen;
usedLen = 0;
buckets = new int[bucketsLen];
//全部初始化为-1,-1代表空桶
for (int i = 0; i < bucketsLen; i++) {
buckets[i] = -1;
}
}
查找
搜索时首先搜索起始同f(k),接着对表中后续桶进行搜索。直到发生以下情况:(1)找到了要搜索的元素;(2)到达一个空桶;(3)又回到f(k)桶。若发生后两种情况,则说明表中没有要搜索元素,返回-1。
public int search(int value) {
int loc = value % bucketsLen;
while (buckets[loc] != value) {
loc++;
loc %= bucketsLen;
if (buckets[loc] == -1 || loc == value % bucketsLen)
return -1;
}
return loc;
}
插入
插入发生冲突时,使用线性开型寻址。当数组已满,则抛出ArrayIndexOutOfBoundsException错误。不要忘记usedLen+1。
public void insert(int value) {
//线性开型寻址
if (usedLen < bucketsLen) {
if (search(value) != -1) {
return;
}
int loc = value % bucketsLen;
while (buckets[loc] != -1) {
loc++;
loc %= bucketsLen;
}
buckets[loc] = value;
usedLen++;
} else {
//表满溢出
throw new ArrayIndexOutOfBoundsException();
}
}
删除
删除时必须保证散列中存在该元素。因为使用的是线性开型寻址,所以在删除后需要逐个检查每个“桶”确定要移动的元素,直到到达一个“空桶”或到达删除操作所对应的“桶”。在删除后移动某个元素时,将其位置置为-1,并重新插入该元素。
public void delete(int value) {
int remainder = value % bucketsLen;
int loc = search(value);
if (loc != -1) {
buckets[loc] = -1;
usedLen --;
loc++;
loc %= bucketsLen;
while (buckets[loc] != -1 && loc != remainder) {
int num = buckets[loc];
buckets[loc] = -1;
insert(num);
usedLen --;
loc++;
loc %= bucketsLen;
}
} else {
throw new NoSuchElementException();
}
}
测试
为方便测试,写了一个print()函数
public void print() {
for (int i = 0; i < bucketsLen; i++) {
System.out.print(buckets[i] + " ");
}
System.out.println();
}
分别进行插入、搜索、删除测试。
public class OpenAddressingHashTest {
public static void main(String args[]) {
int[] testArray = {9, 34, 56, 67, 1, 32, 11, 9, 66};
OpenAddressingHash openAddressingHash = new OpenAddressingHash(10);
System.out.println("插入测试");
//插入测试
for (int i = 0; i < testArray.length; i++) {
openAddressingHash.insert(testArray[i]);
openAddressingHash.print();
}
//查找测试
System.out.println("查找测试");
System.out.println(openAddressingHash.search(56));
openAddressingHash.print();
System.out.println(openAddressingHash.search(1));
openAddressingHash.print();
//删除测试
System.out.println("删除测试");
openAddressingHash.delete(56);
openAddressingHash.print();
}
}
测试结果,结果无误。