有没有办法从下面的数据中唯一地构建一个整数?

时间:2013-10-22 00:32:51

标签: c++ algorithm data-structures hash mathematical-optimization

我有如下结构数据:

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进行排序并构建签名。

我的签名是基于字符串的,如果有办法构建一个唯一的数字签名,那么我的查找/插入会更快。

3 个答案:

答案 0 :(得分:3)

您可以从您拥有的字段中创建唯一的40位数字。为什么40位?我很高兴你问。

您有9,999,999个可能的id值,这意味着您可以使用24位来表示所有可能性(log2(9999999)=略高于23)。

您有9,999个可能的qty值,这需要另外14位。

typeside每个需要1位,这样可以提供总共40位的信息。将此号码存储为long long,您的地图就会有一个漂亮的快捷键。

如果你真的想要一个独特的int密钥,那么你可能会运气不好,因为摆脱8位信息会非常棘手。你可能能够利用qty字段的共同素数来表示它少于14位,但我怀疑你可以将它降低到6位,因为这只能为你提供64个可能的值qty

这是获得你所要求的方法,但是@David Schwartz的答案可能就是你真正需要的答案:除非你有一个非常糟糕的哈希函数,否则哈希冲突通常并不昂贵 - 请参阅Application vulnerability due to Non Random Hash Functions的示例怎么能咬你 - 或者是一个精心设计的数据集,恰好遇到了最坏的情况。

在你的情况下,大卫的回答应该没问题。除非你对你的数据集非常不幸,否则它会足够快。

编辑:刚刚注意到您正在计算5 Legs的集合上的签名。相同的数学运算适用,你只需要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;
}