我有一个非常长的字符串,我需要比较相等。因为比较char char是非常耗时的,所以我喜欢为字符串创建一个哈希。
我喜欢生成的哈希码是唯一的(或者生成相同哈希的两个字符串的机会非常小)。我认为从字符串中创建一个int作为hash不足以消除两个具有相同哈希码的不同字符串,所以我正在寻找一个字符串哈希码。
上述假设我是对的吗?
为了澄清,假设我有一个长度为1K的字符串,我创建了一个10字符的哈希码,然后比较哈希码加速了100倍。
我的问题是如何在c ++中创建这样的哈希码?
我正在使用visual studio 2012开发Windows。
答案 0 :(得分:4)
在这种情况下有用,哈希码必须快速 计算。使用大于最大单词的任何东西 硬件支持(通常是64位)可能是计数器 生产力。不过,你可以尝试一下。我找到了 以下工作得相当好:
unsigned long long
hash( std::string const& s )
{
unsigned long long results = 12345; // anything but 0 is probably OK.
for ( auto current = s.begin(); current != s.end(); ++ current ) {
results = 127 * results + static_cast<unsigned char>( *current );
}
return results;
}
使用这样的哈希可能不会有利, 但是,除非大多数比较都是字符串 不相等,但有很长的共同初始序列。记得 如果哈希相等,你仍然要比较 字符串,这种比较只需要到第一个 字符不相等。 (事实上,大多数比较 我看到的函数从比较长度开始,只进行比较 如果字符串长度相等,则为字符。)
答案 1 :(得分:0)
有许多已知的哈希算法可用。例如MD5,SHA1等。您不需要实现自己的算法,而是使用其中一个可用的算法。使用您选择的搜索引擎查找this one等实现。
答案 2 :(得分:0)
您可以使用许多哈希算法。
如果你想自己实现一个,那么一个简单的方法就是为每个字符取ascii并将其与0对齐(即a = 1,b = 2 ......)并将其与字符索引相乘在字符串中。继续添加这些值并将其存储为特定字符串的哈希值。
例如,abc的哈希值为:
HASH("abc") = 1*1 + 2*2 + 3*3 = 14;
随着弦长增加,碰撞概率降低(考虑到你的琴弦会很长)。
答案 3 :(得分:0)
这真的取决于你的硬性要求。如果您有诸如“搜索可能永远不会超过这么长时间”的硬性要求,那么可能没有适用的解决方案。如果您的意图只是加速大量搜索,那么简单的短哈希就可以了。
虽然通常将1000个字符的字符串散列为整数(单个32位或64位数字),并最终将产生冲突,但这不是关心。
10-charcter哈希也会产生冲突。这是1000&gt;的必然结果。 10.对于每10个字符的散列,存在100个1000个字符的字符串 1 。
重要的问题是你是否真的会看到碰撞,你会看到它们的频率,以及它是否重要。您是否(或有多可能)看到碰撞取决于不字符串的长度,而是取决于不同字符串的数量。
如果使用32位哈希散列77,100个字符串(长度超过4个字符),则每次新哈希都有50%的机会遇到冲突。在25,000弦,可能性只有5-6%左右。在1000弦时,可能性约为0.1%
请注意,当我说“70%在77,100弦”时,不意味着您实际遇到碰撞的几率很高。它只是让两个字符串具有相同哈希值的机会。除非大多数琴弦的情况如此,否则实际击中琴弦的可能性要低得多。
对于大多数使用案例而言,这意味着没有更多也不少于此,这无关紧要。除非你想要散列成千上万的字符串,否则现在不用担心并使用32位哈希 否则,除非你想要哈希数十亿字符串,否则不要担心这里使用64位哈希值。
事情是,你必须准备好处理碰撞 ,因为只要你有2个字符串,碰撞的可能性永远不会为零。即使只有2或3个1000字符的字符串散列为500字节的散列,原则上也会发生冲突(非常不可能,但可能)。
这意味着如果哈希在任何一种情况下都匹配,你必须进行字符串比较,无论你的哈希有多长(或多好或坏)。
如果每次都不发生碰撞,那么它们就完全无关紧要了。如果你的表中有很多冲突并且遇到一个,比如说,在10,000次查找中有1次(这很多!),它没有实际影响。是的,你必须在10,000次查找中进行一次无用的字符串比较,但是另外9,999只通过单独比较一个整数来工作。除非您有严格的实时要求,否则可衡量的影响恰好为零 即使你完全搞砸了并且在每次第5次搜索时都遇到了碰撞(非常糟糕的情况,这意味着大约有8亿个字符串对发生冲突,这种情况只有至少有16亿个字符串可能存在),这仍然意味着5次搜索中有4次没有发生碰撞,因此您仍然会在不进行比较的情况下丢弃80%的非匹配项。
另一方面,生成一个10个字符的哈希很麻烦而且速度很慢,并且您可能会创建一个哈希函数,该哈希函数具有更多冲突(因为设计不当)而不是现有的32或64位哈希 加密哈希函数当然更好,但它们的运行速度也比非加密版本慢,并且存储16或32字节哈希值所需的存储空间也大得多(对大多数人来说几乎没有任何好处)。这是空间/时间的权衡。
就个人而言,我只会使用像djb2这样的东西,它可以在3行C代码中实现,运行良好,运行速度非常快。当然存在许多其他可以使用的哈希函数,但我喜欢djb2的简单性。
有趣的是,在阅读了James Kanze的回答之后,发布的代码似乎是djb2的变体,只有不同的种子和不同的乘数(分别为5381和33)。 在同一个答案中,首先比较字符串长度的说法也是一个很好的建议。值得注意的是,您可以将字符串的长度视为“哈希函数”的一种形式(虽然它是一个相当弱的,但通常是“免费”的)。
<小时/> 1 但是,字符串不是哈希的“随机二进制垃圾”。它们是结构化的低熵数据。就此而言,这种比较并不真实。
答案 4 :(得分:0)
好吧,我首先会比较字符串长度。如果它们匹配,那么我将开始使用一种使用随机位置测试字符相等性的算法进行比较,并在第一个区别时停止。 随机位置将从stringLength大小的向量获得,填充有从0到stringLength-1的随机整数。我没有测量过这种方法,但这只是一个想法。但这可以节省你对哈希冲突的担忧,同时减少比较时间。