【问题标题】:How would you go about designing a function for a perfect hash?您将如何设计一个完美哈希的函数?
【发布时间】:2010-10-18 14:20:53
【问题描述】:

感兴趣的领域是字符串匹配。假设我有这样的结构。

typedef struct
{
    char *name,
    int (*function)();

} StringArray

StringArray s[] = 
{
    {"George", func1},
    {"Paul",   func2},
    {"Ringo",  func3},
    {"John",   func4},
    {"",       NULL}   /* End of list */ 
}

数组中有固定数量的字符串。如示例中所示,它们是硬编码的。 如果表发生变化,则需要重新评估哈希函数的质量。

我想对一个字符串应用一个哈希函数,如果该字符串与数组中的一个匹配, 然后调用函数。为此需要一个完美的哈希函数。不允许发生冲突。要求散列的目的是在查找时获得 O(1) 性能。

你对设计一个功能来做到这一点有什么想法?

【问题讨论】:

标签: c++ c string function hash


【解决方案1】:

你可以使用地图

std::string foo() { return "Foo"; }
std::string bar() { return "Bar"; }

int main()
{
   std::map<std::string, std::string (*)()> m;
   m["foo"] = &foo;
   m["bar"] = &bar; 
}

【讨论】:

  • std::map 不使用哈希 - 它是基于树的
  • 为什么要发明轮子,你可以使用现有的库,比如map。
  • 也许提问者想要的是散列而不是树搜索的性能特征?
  • @Mitch:有什么问题?我们应该经常问自己,不是如何做这个或那个,而是我为什么要使用这个或那个。
  • 没错。为什么 EvilTeach 需要哈希函数?这可能有充分的理由,但我还没有看到它们。对于获取字符串并执行函数的一般情况,这可以正常工作。
【解决方案2】:

如果绝对不允许冲突,您唯一的选择是跟踪数据库中的每个字符串,这可能不是最好的方法。

我要做的是应用现有的一种常见的强哈希算法,例如:MD5 或 SHA。周围有大量样本,例如:http://www.codeproject.com/KB/security/cryptest.aspx

【讨论】:

    【解决方案3】:

    嗯,没有完美的哈希函数。

    您有几个可以最大限度地减少冲突,但没有一个可以消除它们。

    虽然不能推荐一个:P

    编辑: 解决方案不可能是找到一个完美的哈希函数。解决方案是注意碰撞。通常散列函数有冲突。这显然取决于数据集和生成的哈希码的大小。

    【讨论】:

    • @Adam:有一个很大的警告,因为它只适用于不同的数据集。由于 OP 没有提及限制正在使用的字符串,我同意 Megacan 的观点,即在这种情况下没有完美的散列。 +1。
    • 提问者确实提到了这一点,至少是含蓄的——只有四个披头士乐队(如果包括他们解雇的鼓手和 Stu whatsisname 的话)——仍然是一个固定的数据集。
    • 我只是说,解决方案不可能是找到一个完美的哈希函数。解决方案是注意碰撞。通常散列函数有冲突。这显然取决于数据集和生成的哈希码的大小。
    • 是的,这将是一个固定的数据集,他一生只能输入这么多字符串:)。这里的重点是“没有完美的哈希函数”是不言而喻的,除非有明确的约束。 Megacan 在我的书中逻辑上是正确的。
    • @megacan - 按照我发布的答案中的链接进行操作 - 完美的哈希函数是可能的并且被广泛使用
    【解决方案4】:

    使用平衡二叉树。那么你知道的行为总是 O(logn)。

    我非常不喜欢哈希。人们没有意识到他们的算法承担了多大的风险。他们运行一些测试数据,然后在现场部署。我从未见过部署的哈希算法在现场被检查行为。

    O(log n) 几乎总是可以代替 O(1)。

    【讨论】:

    • “用 O(log n) 代替 O(1) 几乎总是可以接受的。”在许多应用程序中,这种说法是完全错误的。只需将数据点的数量增加到几百万以上即可看到这一点。
    • 完成后,进行测试。哈希并不能保证结果,除非您事先知道所有可能的输入是什么。倾向于聚集输入的散列函数可能不会给你 O(1)。
    • 在这种情况下,所有输入都是已知的。他们坐在阵列中。并且输入字符串要么完全匹配,要么不匹配。
    • 不,所有可调度的输入都是已知的。对输入字符串进行哈希处理并获得成功后,您确实需要进行比较。
    • 康拉德 - 是的。但是具有如此多数据的应用程序数量很少而且相差甚远。它们形成了一个特定的、相当罕见的类别。这就是为什么我说几乎总是可以接受的
    【解决方案5】:

    摘要列出了 C 和 C++。你在找他们中的哪一个? C 和 C++ 是两种不同的语言,它们的字符串处理和数据结构有很大不同(C 语言在 C++ 中工作的事实并没有改变这一点)。

    为什么,具体来说,您想要一个完美的哈希函数?您是否想将字符串与函数相关联,并认为这是一个好方法?这是某种家庭作业吗?你有理由不在 C++ 中使用 map 吗? (或者 unordered_map 如果可用?)

    如果您确实需要一个完美的哈希,那么字符串的约束是什么?会有某个固定的系列你想派发吗?与其中一个集合不匹配的字符串怎么办?您愿意接受来自随机字符串的命中,还是输入字符串的数量受到限制?

    如果您可以编辑您的问题以包含此类信息,我们可能会更有帮助。

    编辑(响应前两个 cmets):

    好的,我们应该看看 C 解决方案,因为您可能希望在您的 C 和 C++ 工作中都使用它。您大概想要性能,但是您测试过吗?如果我们正在处理进入 I/O 系统的字符串,那么那里的时间可能会使调度时间相形见绌。

    您期待任意字符串。期望一个完美的哈希函数可以避免随机数据的所有冲突有点过分,所以你需要考虑这一点。

    你考虑过trie吗?它可能比完美的散列函数更有效(或者可能不是),它应该很容易在 C 中实现,并且可以避免重做调度字符串列表或可能的冲突。

    【讨论】:

    • 我用 c 和 c++ 编写代码,上帝帮助我 Pro*C。 O(1) 散列以提高性能。大声笑,没有家庭作业。我正在寻找一个工具来加速一些性能关键的代码。为了讨论的目的,这个例子很简单。现实世界的用途不是。
    • 字符串会很长。它们都不会是长度为零的。作为实际限制,数组中的任何字符串都不会超过 32 个字符。调用者传入的内容可以是任意长度,但如果它比表中的字符串长,则为不匹配的情况
    【解决方案6】:

    这个练习的最终结果是

    • 从网上窃取大量面向字符串的哈希函数。
    • 构建一种工厂类,使用一系列 mod 运算符值针对数据集测试每个函数,寻找适用于该函数的最小完美哈希。
    • 该工厂类默认构造函数返回一个字符串,该字符串表示一组参数,在使用时选择正确的散列函数和 mod 大小以提供需要最少内存的完美散列。
    • 在正常使用情况下,您只需使用返回的参数实例化类,该类将自身置于具有所需功能的工作状态。
    • 该构造函数验证没有冲突,如果有则中止。
    • 在找不到完美哈希的情况下,它会降级为对输入表的排序版本进行二进制搜索。

    对于我在我的域中拥有的一组数组,这似乎工作得非常好。 未来可能的优化是对输入的子字符串进行相同类型的测试。在示例案例中,每个音乐家姓名的第一个字母足以区分他们。然后需要平衡实际哈希函数的成本与 使用的内存。

    感谢所有贡献想法的人。

    邪恶

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-05
      • 1970-01-01
      • 2023-03-03
      • 2019-05-22
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      相关资源
      最近更新 更多