在我的哈希表实现中,我的哈希函数只是获取我传递的项的值,调用hashCode(继承自Object类),并以内部数组的大小为模。此内部数组是LinkedLists数组。现在,如果我的LinkedLists变得太长(并且我的效率开始从O(1)滑落到O(n)),我认为简单地增加数组的大小是有意义的。但这就是我的问题所在,因为我说我散列了我传递的项目并模数数组的大小(刚刚更改)。如果我要继续,哈希是否会指向数组中的不同索引,从而失去引用哈希表中的项目的能力?我怎么能解决这个问题?
答案 0 :(得分:1)
您需要每个项目的实际哈希值,以便您可以将它们放入已调整大小的表中的正确哈希链中。 (否则,正如您所观察到的那样,这些物品可能最终会出现在错误的链条上,并且因此无法定位。)
有两种方法可以解决这个问题:
您可以在将每个项目添加到新表格时重新计算每个项目的哈希值。
您可以保留哈希链中每个项目的原始哈希值的副本。这就是标准的Java HashMap
实现所做的...至少在我看过的版本中。
(后者是时间与空间的权衡,如果你的物品有昂贵的hashcode
方法,那么可以支付大笔时间。但是,如果你在一生中分期付款,那么哈希表,这种优化不会改变任何公共API方法的“大O”复杂性...假设你的哈希表大小调整是指数级的;例如你每次大约两倍的表大小。)
答案 1 :(得分:0)
package com.codewithsouma.hashtable;
import java.util.LinkedList;
public class HashTable {
private class Entry {
private int key;
private String value;
public Entry(int key, String value) {
this.key = key;
this.value = value;
}
}
LinkedList<Entry>[] entries = new LinkedList[5];
public void put(int key, String value) {
var entry = getEntry(key);
if (entry != null){
entry.value = value;
return;
}
getOrCreateBucket(key).add(new Entry(key,value));
}
public String get(int key) {
var entry = getEntry(key);
return (entry == null) ? null : entry.value;
}
public void remove(int key) {
var entry = getEntry(key);
if (entry == null)
throw new IllegalStateException();
getBucket(key).remove(entry);
}
private LinkedList<Entry> getBucket(int key){
return entries[hash(key)];
}
private LinkedList<Entry> getOrCreateBucket(int key){
var index = hash(key);
var bucket = entries[index];
if (bucket == null) {
entries[index] = new LinkedList<>();
bucket = entries[index];
}
return bucket;
}
private Entry getEntry(int key) {
var bucket = getBucket(key);
if (bucket != null) {
for (var entry : bucket) {
if (entry.key == key) return entry;
}
}
return null;
}
private int hash(int key) {
return key % entries.length;
}
}