好的,我有一个项目要求我有一个动态哈希表来计算文件中单词的频率。我必须使用java,但是,除标准数组外,我们不允许使用任何内置数据类型或内置类。此外,我不允许在互联网上使用任何已知速度快的哈希函数。我必须自己创建哈希函数。最后,我的导师还希望我的桌子从尺寸开始#1;#"每次添加新密钥时,大小加倍。
我的第一个想法是将构成单词的字母的ASCII值相加并使用它来制作散列函数,但具有相同字母的不同单词将等于相同的值。
我该如何开始? ASCII想法是否正确?
答案 0 :(得分:1)
哈希表通常不会一般一个值和一个哈希之间的一对一映射。哈希表预计会发生冲突。也就是说,期望散列函数的域大于范围(即,散列值)。但是,一般的想法是你提出了一个哈希函数,其中碰撞的概率非常小。如果您的哈希函数是统一的,即,如果您将其设计为使得每个可能的哈希值具有相同的生成概率,那么您可以通过这种方式最小化冲突。
发生碰撞并不是世界末日。这只意味着您必须搜索该哈希值的列表。如果您的散列函数很好,那么整体查找性能仍应为O(1)。
生成散列函数是它自己的主题,没有一个答案。但是你开始的一个好地方可能是使用字符串中字符的按位表示,并对它们执行某种卷积操作(旋转,移位,XOR)。您可以基于某些初始种子值以某种方式执行这些操作,然后使用散列的第一步输出作为下一步的种子。通过这种方式,您最终可以放大卷积的效果。
例如,假设您获得了字符A
,其中十六进制为41
,二进制为0100 0001
。您可以将每个位指定为某个操作(当0为0时,位0为ROR,1为时为ROL; 0为0时为0,如果为1则为XOR等) 。您甚至可以根据值本身来决定要进行多少卷积。例如,您可以说较低的半字节指定您将进行多少右旋转,而较高的半字节指定您将进行多少左旋转。然后,一旦得到最终值,您将使用它作为下一个字符的种子。这些只是一些想法。用你的想象力来看看你得到了什么!
答案 1 :(得分:0)
你的哈希函数有多好并不重要,你总会遇到需要解决的冲突。
如果你想通过使用ASCII值来保持你的方法,你不应该只添加值,这将导致很多冲突。您应该使用值的功能,例如“帮助”这个词就像:'H'* 256 +'e'* 256 +'l'*256²+'p'*256³。或者在伪代码中:
int hash(String word, int hashSize)
int res = 0
int count = 0;
for char c in word
res += 'c' * 256^count
count++
count = count mod 5
return res mod hashSize
现在你只需编写自己的Hashtable:
class WordCounterMap
Entry[] entrys = new Entry[1]
void add(String s)
int hash = hash(s, entrys.length)
if(entrys[hash] == null{
Entry[] temp = new Entry[entry.length * 2]
for(Entry e : entrys){
if(e != null)
int hash = hash(e.word, temp.length)
temp[hash] = e;
entrys = temp;
hash = hash(s, entrys.length)
while(true)
if(entrys[hash] != null)
if(entrys[hash].word.equals(s))
entrys[hash].count++
break
else
entrys[hash] = new Entry(s)
hash++
hash = hash mod entrys.length
int getCount(String s)
int hash = hash(s, length)
if(entrys[hash] == null)
return 0
while(true)
if(entrys[hash].word.equals(s))
entrys[hash].count++
break
hash++
hash = hash mod entrys.length
class Entry
int count
String word
Entry(String s)
this.word = s
count = 1