我有如下结构数据:
struct Leg
{
char type;
char side;
int qty;
int id;
} Legs[5];
其中
type is O or E,
side is B or S;
qty is 1 to 9999 and qty in all Legs is relative prime to each other i.e. 1 2 3 not 2 4 6
id is an integer from 1 to 9999999 and all ids are unique in the group of Legs
要构建上述数据的唯一签名,目前我正在构建如下字符串: 首先根据id排序Legs; 那么
signature=""
for i=1 to 5
signature+=id+type+qty+side of leg-i
我插入到unordered_map中,这样如果有任何匹配的结构化数据出现,我可以通过建立上面的签名并查找来查找。
字符串上的unorderd_map表示密钥比较,它是字符串比较,也是需要遍历通常大约25个字符的字符串的哈希函数。
为了提高效率,可以为上面的每个结构从上面的数据中构建一个唯一的整数,unorderd_map中的查找/插入将非常快。
只是想知道我是否可以利用任何数学属性。
编辑: 地图将包含键值对,如
<unique-signature=key, value=int-value needs to be located on looking up another repeating Leg group by constructing signature like above after sorting Legs based on id>
<123O2B234E3S456O3S567O2S789E2B, 989>
目标是从每个这样独特的重复腿组建立独特的签名。腿可以按不同的顺序排列,但它们可以与另一组腿匹配,这些腿的顺序不同,这就是为什么我根据唯一的ID进行排序并构建签名。
我的签名是基于字符串的,如果有办法构建一个唯一的数字签名,那么我的查找/插入会更快。
答案 0 :(得分:3)
您可以从您拥有的字段中创建唯一的40位数字。为什么40位?我很高兴你问。
您有9,999,999个可能的id
值,这意味着您可以使用24位来表示所有可能性(log2(9999999)=略高于23)。
您有9,999个可能的qty
值,这需要另外14位。
type
和side
每个需要1位,这样可以提供总共40位的信息。将此号码存储为long long
,您的地图就会有一个漂亮的快捷键。
如果你真的想要一个独特的int
密钥,那么你可能会运气不好,因为摆脱8位信息会非常棘手。你可能能够利用qty
字段的共同素数来表示它少于14位,但我怀疑你可以将它降低到6位,因为这只能为你提供64个可能的值qty
。
这是获得你所要求的方法,但是@David Schwartz的答案可能就是你真正需要的答案:除非你有一个非常糟糕的哈希函数,否则哈希冲突通常并不昂贵 - 请参阅Application vulnerability due to Non Random Hash Functions的示例怎么能咬你 - 或者是一个精心设计的数据集,恰好遇到了最坏的情况。
在你的情况下,大卫的回答应该没问题。除非你对你的数据集非常不幸,否则它会足够快。
编辑:刚刚注意到您正在计算5Legs
的集合上的签名。相同的数学运算适用,你只需要200位而不是4.所以它不适合long long
,除非你有一些信息可以在所有5个Leg
对象之间共享;例如,如果每组5个共享相同的id
。
坚持大卫的回答。
答案 1 :(得分:2)
它不一定是唯一的。我会建议像:
std::size_t hash_value(const Leg& l)
{
std::size_t ret = l.type;
ret << = 8;
ret |= l.side;
ret *= 2654435761;
ret += l.qty;
ret *= 2654435761;
ret += l.id;
return ret * 2654435761;
}
答案 2 :(得分:1)
为了为五条腿创建一个与顺序无关的哈希函数,首先为各个腿选择哈希函数 - David's answer看起来很棒。计算五条腿中每条腿的哈希值。现在选择一个与顺序无关的函数来组合这五个哈希值。例如,你可以将哈希值合并在一起,或者将它们全部加在一起,或者将它们全部加在一起。
乘法分布超过加法,乘法是最后一次发生的操作,这让我对使用它有点警惕。我认为xor可能是我在这里给出的最佳选择;但在生产中使用它之前,你应该运行一些测试,看看是否可以轻松地与它们中的任何一个产生碰撞。
可能是多余的,但这是一个从David's answer调用hash_value
的简单实现:
std::size_t hash_value(const Leg_Array& legs) {
std::size_t ret = 0;
for (int i = 0; i < 5; ++i) {
ret ^= hash_value(legs[i]);
}
return ret;
}