所以我正在开发一个使用哈希表的程序。这是怎么回事:
1)将文本文件读入“符号”对象的向量(包含名称和数字) 2)散列Symbol对象的名称。 3)将此对象插入哈希表。
到目前为止,我一直将唯一生成的哈希键存储为整数数组。然后我循环遍历数组,看看是否有重复。
如果有,我知道发生了碰撞。这个方法已被证明是成功的,但是现在我必须编写一个rehash()函数,这样我就可以获得一个不会导致冲突的新密钥。但我无法弄清楚如何做到这一点。
我已经包含了我的循环,我检查了键的数组和我当前的散列函数以及输出。任何关于去哪里的建议都会非常感激。
for (int i=0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (array[i] == array[j])
{
cout << endl;
cout << "Collision occurred at" << array[i] << endl;
cout << "Now rehashing..." << endl;
// REHASH FUNCTION SHOULD GO HERE --> rec.key = rehash(data);
cout << "The new key is: " << rec.key << endl;
break;
}
}
}
dataTable.insert(rec); //inserts the record object into the HashTable.
现有哈希函数:
int hasher (string data)
// POST: the index of entry is returned
{ int sum = 0;
for (int k = 0; k < data.length(); k++)
sum = sum + int(data[k]);
return sum % TABLE_SIZE;
}
输出我正在:
计数 2 此Symbol对象的关键是:7
num
2
The key for this Symbol object is: 0
Collision occurred at0
Now rehashing...
The new key is: 1
myFloat
4
The key for this Symbol object is: 18
myDouble
5
The key for this Symbol object is: 14
name
6
The key for this Symbol object is: 18
Collision occurred at18
Now rehashing...
The new key is: 1
address
6
The key for this Symbol object is: 7
Collision occurred at7
Now rehashing...
The new key is: 1
salary
5
The key for this Symbol object is: 1
gpa
4
The key for this Symbol object is: 18
Collision occurred at18
Now rehashing...
The new key is: 1
gdp
5
The key for this Symbol object is: 0
Collision occurred at0
Now rehashing...
The new key is: 1
pi
5
The key for this Symbol object is: 7
Collision occurred at7
Now rehashing...
The new key is: 1
city
6
The key for this Symbol object is: 0
Collision occurred at0
Now rehashing...
The new key is: 1
state
6
The key for this Symbol object is: 20
county
6
The key for this Symbol object is: 2
ch
0
The key for this Symbol object is: 14
Collision occurred at14
Now rehashing...
The new key is: 1
ch2
0
The key for this Symbol object is: 1
Collision occurred at1
Now rehashing...
The new key is: 1
ID
1
The key for this Symbol object is: 15
studentID
1
The key for this Symbol object is: 13
max
3
The key for this Symbol object is: 11
max2
3
The key for this Symbol object is: 19
greeting
6
The key for this Symbol object is: 13
Collision occurred at13
Now rehashing...
The new key is: 1
debt
5
如您所见,当发生碰撞时,它会成功检测到它。现在我只需要一种方法来再次重新使用密钥,以便将来不会发生...因为现在重新散列也是一种冲突。
答案 0 :(得分:2)
解决哈希冲突的简单方法是separate chaining。基本上,您的数据结构有一堆链表,因此当发生冲突时,您只需将结果附加到此处发生冲突的其他值。还有其他方法具有更高效的插入/查找时间,但显然,它们需要更多的努力来实现。
答案 1 :(得分:1)
说你的数组是:
#define N ...
struct element table[N];
然后你可以定义两个哈希函数(独立!),让我们说int h(data); int g(data);
0 <= h < N
和1 <= g < N
。确保g
返回的值相对于N
的素数。然后,要插入新元素,请执行以下操作:
int i = h(data);
if(table[i] is free)
/* Go ahead! */
else {
/* Was occupied, try alternatives */
int j = g(data);
for(k = i + j; k != i; k = (k + j) % N)
if(table[k] is free) {
/* Found a free space, go ahead */
break;
}
if(k == i) {
/* Table is full */
}
}
搜索类似。
将g
的值始终相对优先N
的最简单方法是采用1.稍微更难确保N
为素数,{{1} }总是小于g
。
使用N
会使数据聚集起来,从而减慢搜索速度;不同的g == 1
值可以避免这种情况。
答案 2 :(得分:1)
所以我正在研究一个使用哈希表的程序。这是怎么回事:
1)将文本文件读入&#34;符号&#34;的矢量。对象(包含名称和数字)2)散列符号对象的名称。 3)将此对象插入哈希表。
到目前为止,我一直将唯一生成的哈希键存储为整数数组。然后我循环遍历数组,看看是否有重复。
如果有,我知道那里发生了碰撞。这种方法已被证明是成功的,但是现在我必须写一个rehash()函数,这样我就可以获得一个不会导致碰撞的新密钥。
我不确定您是否正在尝试实施NIST呼叫double-hashing,2-choice hashing或cuckoo hash的内容。我认为你在谈论双重哈希。
如果你知道所有可能的输入,你可以选择两个具有你正在寻找的属性的哈希。当然,如果您知道每个可能的输入,您可以选择一个没有任何冲突的哈希。
如果您不关心性能,可以选择两种不同的加密安全散列函数,例如SHA3和Skein。但是,我非常怀疑你是否想要这样。当博客讨论the meet-in-the-middle vulnerability in a widely-used hash function时,我认为最简单的解决方案是使用一种功能 - 例如加密安全散列函数 - 设计为抗冲突。我所知道的最简单的哈希函数,我认为适合该法案TEA,比它要替换的函数慢十倍。请注意:TEA对其他任何东西都不安全,因为它对于哈希映射来说是一个糟糕的选择,所以很难找到任何用途。
你可以选择两个狂野的different hash functions并希望最好。
有SipHash,由密码学家设计,即使它不具有加密安全性,也具有抗冲突性。但是,not everyone's happy with its performance(部分&#34;动态语言的哈希函数&#34;)。另外,我对SipHash竞赛中的任何类似分析并不熟悉,所以虽然我很乐意将你指向SipHash,但我还是不习惯推荐第二个哈希。
我更愿意使用不同的方法来处理碰撞。你想做的事情并没有错,但是它已经走了很多路,很难找到好的建议。
所以,我的推荐(按优先顺序)是:
std::unordered_map
。不幸的是,当您可以替换std::unordered_map
使用的哈希函数时,这很痛苦。std::vector
(对于CPU缓存很好,添加/删除元素会更麻烦)或std::list
用于列表)。此方法已被证明是成功的,但是现在我必须编写一个rehash()函数,这样我就可以得到一个不会导致碰撞的新密钥。但我无法弄清楚如何做到这一点。
我已经包含了我的循环,我检查了键数组和我当前的散列函数以及输出。任何关于去哪里的建议都会非常感激。
简而言之:
rehash()
方法 ,如果rehash()
建议的插槽为空,则放置该项那里;否则,请致电rehash(rehash(key))
,然后继续这样做,直到找到一个空插槽(至少,这是我如何在双重散列上取消NIST页面)hash(key)
返回一个空插槽,则表示您已完成;如果hash(hey)
返回包含您要查找的项目的广告位,则表示您已完成;它hash(key)
会返回包含不同商品的广告位,然后您必须致电rehash(key)
和rehash(rehash(key))
等,直到找到您正在寻找的内容或找到空位< / LI>
rehash()
来查看如果您要查找的元素在地图中<#34; 如果这看起来令人生畏,请重新考虑std::unordered_map
是否适合该法案。
我现在可以推荐除SipHash之外的抗冲突哈希(或者,事实上,several)。
答案 3 :(得分:0)
rehash可能很简单,比如在表大小中添加一个相对素数的数字到索引(开放寻址)。将密钥添加到哈希表时,可能需要多次重新查找哈希表中的可用索引。
答案 4 :(得分:0)
当你看到实现一个没有冲突的哈希函数时,你需要多年的研究。总而言之,你正试图实现完美的哈希。
您实施的内容称为链接解决冲突。 这个过程的缺点是每当发生碰撞时,搜索采用O(n)的最坏情况时间,其中n是子链中元素的数量
以下是选择has函数的方法
1)分工方法
2)乘法方法
3)通过开放式寻址解决冲突
4)探索策略
5)普遍哈希。 (碰撞概率无限低的情况)
6)完美的哈希。 (只有在某些情况下才有可能)。
请参阅第7讲和第8讲
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-046j-introduction-to-algorithms-sma-5503-fall-2005/video-lectures/
为了更深入地了解上述方法,如果您有兴趣编写自己的通用哈希函数,我认为您从讲座中获得的知识将是一个很好的起点。
一切顺利