假设您有这两个字符串序列
abc cba bc
bc abc cba
我正在尝试为这些序列创建一个映射(序列也是一个字符串),以便上面两个序列映射到同一个桶中。
我最初的想法是添加分别应用于每个字符串的散列函数的结果。这样他们的顺序无关紧要。如果我将散列函数作为一个整体应用于序列字符串,那么散列结果当然会有所不同。
然而,我对字符串散列函数的世界很新,我不知道这种方法是否有效。
在本网站http://www.partow.net/programming/hashfunctions/index.html
我发现了很多不同的字符串哈希实现,但是我不确定哪一个对我的需求来说是“最好的”。
序列中每个字符串的一些技术细节是每个字符串不超过25个字符。此外,每个序列的字符串不会超过3个。
问题
1.
这种方法是将字符串散列函数的结果添加到序列的每个字符串中吗?
2.
如果是,我应该使用哪个字符串哈希函数,这会产生少量的冲突并且也是时间效率的?
提前谢谢
答案 0 :(得分:2)
只是想法演示(非常低效的字符串复制),复杂度O(NlogN),其中N是键的大小(=== O(1),如果你的键在编译时已知长度不变),我不知道认为你可以做更好的复杂性:
#include <boost/functional/hash.hpp>
#include <set>
#include <algorithm>
std::size_t make_hash(
std::string const& a,
std::string const& b,
std::string const& c)
{
std::string input[] = {a,b,c};
std::sort(input, input + (sizeof(input)/sizeof(*input)));
return boost::hash_range(input, input + (sizeof(input)/sizeof(*input)));
}
#include <iostream>
// g++ -I.../boost_1_47_0 string_set_hash.cpp
int main()
{
std::cout << make_hash("abc", "bcd", "def") << std::endl; // 46247451276990640
std::cout << make_hash("bcd", "def", "abc") << std::endl; // 46247451276990640
}
boost / functional / hash.hpp的片段供参考:
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
boost::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
template <class It>
inline std::size_t hash_range(It first, It last)
{
std::size_t seed = 0;
for(; first != last; ++first)
{
hash_combine(seed, *first);
}
return seed;
}
答案 1 :(得分:0)
无论你选择哪种散列函数,你都需要一个运算符来表示每个散列的最终组合:
总和,产品和排他性或想到作为整数值的候选者。所以是的,添加会起作用。你仍然会遇到需要解决的无关序列的冲突,所以你需要一个字符串比较函数,但同一组字符串的排列最终会在同一个桶中。
你也可以颠倒操作顺序:首先在字符串中添加字符串(例如,添加“ab”和“cba”变为('a'+'c')('b'+'b')( '\ 0'+'a')带有sum或product的进位传播,因此xor或许是一个有趣的候选者,然后应用哈希函数。您甚至可以在执行这两个操作时将它们组合在一起(伪代码如下):
int hash(string a, string b, string c){
int r = 0, k;
int m = max(a.length(), max(b.length(), c.length()));
for (int i = 0; i < m; i++) {
k = ( i < a.length()? a[i] : 0) ^
(i < b.length()? b[i] : 0) ^
(i < c.length()? c[i] : 0);
r = hash(r,k);
}
return r;
}
使用hash
增量散列函数。对于足够大的素数(即大于桶阵列的预期大小)的简单模数应该可以用于正常目的。
一个完全不同(更好的?)解决方案是简单地对序列进行排序(3个条目意味着准恒定时间),然后使用比较函数制作有序映射,将字符串视为3位数字的“数字”。但这超出了问题的范围。
答案 2 :(得分:0)
我会单独散列每个元素。
然后对那些哈希进行排序。排序3 size_t
很快。
然后将这些哈希链接起来。您的库可能具有哈希链函数,甚至可以使用带溢出包的hash( a+b+c )
。
避免使用xor,因为xor两个相同的哈希值为零。并且相同字符串的哈希是相同的。因此,天真的xor可能导致( a,a,b )
和( c,c,b )
具有相同的哈希输出,这很糟糕。