【问题标题】:Is there a way to uniquely build an integer from below data?有没有办法从下面的数据中唯一地构建一个整数?
【发布时间】:2013-10-30 16:29:52
【问题描述】:

我有如下结构化数据:

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 on string 表示 key-compare 是字符串比较,也是哈希函数,需要遍历通常在 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 进行排序并构建签名。

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    typeside 各需要 1 位,这样一共有 40 位信息。将此号码存储为long long,这样您的地图就有了一个不错的快速键。

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

    这是一种获得您所要求的方法,但@David Schwartz 的答案可能是您真正需要的:哈希冲突通常并不昂贵,除非您有一个非常糟糕的哈希函数 - 请参阅 Application vulnerability due to Non Random Hash Functions 以获取有关如何实现的示例可能会咬到你 - 或精心设计的数据集碰巧遇到最坏的情况。

    在您的情况下,您应该可以接受大卫的回答。除非您对自己的数据集非常不满意,否则它会足够快。

    编辑:刚刚注意到您正在计算您的签名集 5 Legs。同样的数学适用,您只需要 200 位而不是 4 位。因此它不适合 long long,除非您有一些可以在所有 5 个 Leg 对象之间共享的信息;例如,如果每组 5 个共享相同的id

    坚持大卫的回答。

    【讨论】:

    • 可能是我的问题没有说清楚 1.签名需要从所有的腿中生成。 2.我需要在哈希表中为每个这样独特的重复腿组(腿可以以不同的顺序)存储一个int值,这个想法是查找该值,因此在发生碰撞时键需要是唯一的,我需要找到我认为使用 KeyEqual 函数找到的那个键的值。 3.我生成字符串签名的方式始终是唯一的,但问题在于效率、动态分配和字符串比较,因此需要一种从 Legs 组中生成唯一整数的方法。
    • 不幸的是,重复组中的每条腿都可能有不同的值并且不可预测
    【解决方案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;
    }
    

    【讨论】:

    • 可能是我的问题没有说清楚 1.签名需要从所有的腿中生成。 2.我需要在哈希表中为每个这样独特的重复腿组(腿可以以不同的顺序)存储一个int值,这个想法是查找该值,因此在发生碰撞时键需要是唯一的,我需要找到我认为使用 KeyEqual 函数找到的那个键的值。 3.我生成字符串签名的方式始终是唯一的,但问题在于效率、动态分配和字符串比较,因此需要一种从 Legs 组中生成唯一整数的方法。
    • 这个哈希函数叫什么名字?只是感兴趣。
    • Knuth 的乘法散列。
    【解决方案3】:

    为了为五个分支的组创建一个与顺序无关的散列函数,首先为单个分支选择一个散列函数 -- 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;
    }
    

    【讨论】:

    • 对不起,我需要从一组腿中生成一个唯一的数字,即对于每组腿来说,hash_value 需要是唯一的,不应该有冲突,因为我打算将此计算的哈希存储为 类型映射中的键和关联的整数值。每组独特的腿都与一个 int 值相关联。因此,我不想存储 的映射,这对于键比较和 Legs 占用大量空间是昂贵的,我想通过计算来自 Legs 的唯一整数来存储 ,该整数对于每个不同的集合都是唯一的腿。
    • 不可能:正如 Cameron 上面所展示的,一条 Leg 中大约有 40 位信息,因此在 5 个 leg 的元组中大约有 200 位信息。任何到 64 位整数的映射都会发生冲突。从理论上讲,您可以制定一个方案来将数据放入 BigInt 或至少 200 位宽的整数数组中......但我不确定这是否会特别好。
    猜你喜欢
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    相关资源
    最近更新 更多