【问题标题】:Two-way "Hashing" of string字符串的双向“散列”
【发布时间】:2011-12-18 07:45:58
【问题描述】:

我想从字符串生成 int 并能够将其生成回来。 类似于散列函数但双向函数的东西。 我想在我的应用程序中使用整数作为 ID,但希望能够在记录或调试时将其转换回来。

喜欢:

int id = IDProvider::getHash("NameOfMyObject");

object * a = createObject(id);

...

if(error)
{
    LOG(IDProvider::getOriginalString(a->getId()), "some message");
}

听说CRC32稍作修改,速度快,100%可逆,但是找不到,自己也写不出来。

任何提示我应该使用什么? 谢谢!

编辑 我刚刚创建了我拥有整个 CRC32 的来源:

Jason Gregory:游戏引擎架构

引用:

“与任何散列系统一样,冲突是可能的(即,两个不同的字符串可能以相同的散列码结束)。但是,使用合适的散列函数,我们几乎可以保证不会发生冲突我们可能会在游戏中使用的合理输入字符串。毕竟,一个 32 位的哈希 chode 代表了超过 40 亿个可能的值。因此,如果我们的哈希函数能够很好地在这个非常大的范围内分配字符串,我们不太可能碰撞。在顽皮狗,我们使用 CRC-32 算法的变体来散列我们的字符串,在 Uncharted: Drake's Fortune 的两年多的开发中,我们没有遇到过一次碰撞。”

【问题讨论】:

  • 这不是散列的意思。
  • 你在说这个吗?只有 CRC32 的一种特殊情况是可逆的:stackoverflow.com/questions/1514040/reversing-crc32
  • no crc32 不会像你想的那样做,它的主要目的是检测位错误。
  • @SLaks 我知道散列是什么意思,但我找不到其他词。这就是为什么我使用引号,写something like并使用术语two-way
  • 这不会给出一个 int,并且它不绑定到 C++,但是为了搜索,人们可能对 base64 编码感兴趣(例如在 bash 中,echo whatever|base64 给出 d2hhdGV2ZXIK,它base64 -d 解码回whatever)。

标签: c++ hash


【解决方案1】:

你可以看看完美的散列

http://en.wikipedia.org/wiki/Perfect_hash_function

只有在预先知道所有潜在字符串时才有效。在实践中,您通过此启用的是创建一个有限范围的“哈希”映射,您可以反向查找。

一般来说,[哈希码+哈希算法]永远都不足以取回原始值。但是,使用完美哈希,根据定义排除了冲突,因此如果源 (值列表)已知,则可以取回源值。

gperf 是一个著名的古老程序,用于在 c/c++ 代码中生成完美的哈希值。确实存在更多(参见维基百科页面)

【讨论】:

  • 在实践中,我几乎总是会拿一本字典来解决这个问题。但有时它可能会带来性能优势。
  • 同意。不过,一个好处是可以共享散列函数。现在,任何客户端都可以得出正确的哈希和,而无需知道可能输入值的完整表。这对于源域相对较大的分布式软件来说是一大福音
【解决方案2】:

将任意长度的字符串缩减为固定大小的 int 在数学上是不可能逆转的。见Pidgeonhole principle。字符串的数量几乎是无限的,但只有 2^32 个 32 位整数。

32 位哈希(假设您的 int 是 32 位)很容易发生冲突。所以它也不是一个好的唯一 ID。

有一些散列函数允许您使用预定义的散列创建消息,但它很可能不是原始消息。这称为pre-image

对于您的问题,最好的办法是创建一个字典,将整数 ID 映射到字符串并返回。


要在对 n 个字符串进行哈希处理时获得冲突的可能性,请查看 the birthday paradox。在这种情况下,最重要的属性是,一旦散列消息的数量接近可用散列值数量的平方根,就可能发生冲突。因此,如果您散列大约 65000 个字符串,则可能会发生 32 位整数冲突。但如果你不走运,它可能会更早发生。

【讨论】:

  • 感谢您的回答。由于各种原因,我不想用字典制作它。我对一些哈希函数的修改很好奇,请看我的问题的编辑
  • @relax 冲突概率取决于您散列的字符串数量和散列大小。如果您不希望发生实际冲突,我建议使用 128 位 + 哈希。但是你仍然不会轻易取回原来的字符串。
【解决方案3】:

不可能。散列是不可返回的函数 - 根据定义。

【讨论】:

    【解决方案4】:

    您需要的是加密。根据定义,散列是一种方式。您可以尝试简单的 XOR 加密和一些值的加法/减法。

    ...以及更多通过谷歌搜索...

    【讨论】:

    • 我知道哈希函数是一种方法。这就是我写modification of hash function 的原因。请查看我的问题的编辑
    【解决方案5】:

    我有你需要的。它被称为“指针”。在这个系统中,“指针”总是唯一的,并且总是可以用来恢复字符串。它可以“指向”任何长度的任何字符串。作为奖励,它的大小也与您的 int 相同。您可以使用& 操作数获取指向字符串的“指针”,如我的示例代码所示:

    #include <string>
    int main() {
        std::string s = "Hai!";
        std::string* ptr = &s; // this is a pointer
        std::string copy = *ptr; // this retrieves the original string
        std::cout << copy; // prints "Hai!"
    }
    

    【讨论】:

    • +1 表示配方。 :) 虽然,公平地说,指针值在运行之间不会相同。
    • 这有很多问题:1)ID 只能在单个进程中使用 2)您需要使字符串保持足够长的时间 3)如果您将其应用于多个相等的字符串内容明智,但不参考明智,您会得到不同的 ID。
    • @CodeInChaos 谢谢,我正要自己写呢
    • @CodeInChaos:可以使用boost获取进程间指针。您还可以使用其他类型的智能指针来序列化指针。其次,无论如何他只会使用几个常量字符串,所以生命周期和引用问题并不是什么大问题。
    • "作为奖励,它的大小也与您的 int 相同。" I32LP64 不同意
    【解决方案6】:

    正如大家所提到的,不可能有“可逆哈希”。但是,还有其他选择(例如加密)。

    另一种方法是使用任何无损算法压缩/解压缩字符串。

    这是一种简单、完全可逆的方法,不会发生碰撞。

    【讨论】:

      猜你喜欢
      • 2011-12-25
      • 2011-09-30
      • 2020-03-17
      • 1970-01-01
      • 2017-05-03
      • 2014-03-25
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      相关资源
      最近更新 更多