为一组整数生成id

时间:2009-08-30 09:43:11

标签: algorithm math hash

背景:

我正在处理整数序列{0,1,2 ...,n}的排列。 我有一个局部搜索算法,以某种系统的方式将排列转换为另一种排列。该算法的要点是产生最小化成本函数的置换。我想解决各种各样的问题,从n = 5到n = 400。

问题:

为了减少搜索工作,我需要能够检查我之前是否处理过特定的整数排列。我正在使用哈希表,我需要能够为每个排列生成一个id,我可以将其用作表中的键。但是,我想不出任何好的哈希函数将一组整数映射到一个键中,这样就不会太频繁地发生冲突。

我试过的东西:

我首先生成一个n个素数序列,然后将我的排列中的第i个数乘以第i个素数,然后对结果求和。但是,即使n = 5,生成的密钥也会产生冲突。

我还想将所有数字的值连接在一起,并将结果字符串的整数值作为键,但即使对于小的n值,id也会很快变得太大。理想情况下,我希望能够将每个键存储为整数。

stackoverflow对我有什么建议吗?

10 个答案:

答案 0 :(得分:7)

Zobrist hashing可能适合您。您需要创建一个随机整数的NxN矩阵,每个单元表示该元素i位于当前排列的第j个位置。 对于给定的排列,您可以选择N个单元格值,并逐个xor来获取排列的关键字(请注意,不保证密钥唯一性)。

此算法的要点是,如果您交换排列中的元素,则可以通过简单地排除新位置中的旧值和xor-ing来轻松地从当前排列生成新密钥。

答案 1 :(得分:6)

根据您的问题判断,以及您留下的评论,我会说您的问题无法解决。

让我解释一下。

你说你需要一个独特的哈希组合,所以让我们制定规则#1:

  • 1:需要一个唯一的数字来表示任意数量的数字/数字的组合

好的,然后在评论中你已经说过,因为你使用了很多数字,因为内存限制,将它们存储为字符串或诸如哈希表的关键字是不可行的。所以让我们把它重写成另一条规则:

  • 2:无法使用用于生成哈希的实际数据,因为它们已不在内存中

基本上,你试图占用大量数字,并将其存储到一个小得多的数字范围内,并且仍然具有唯一性。

抱歉,但你做不到。

典型的哈希算法会产生相对独特的哈希值,所以除非你愿意接受冲突,否则新组合可能会被标记为“已经看到”,即使它没有,那么你就不在了运气。

如果你要尝试一个位字段,每个组合都有一个位,如果没有看到它就是0,你仍然需要大量的内存。

对于你在评论中留下的n = 20的排列,你有20个! (2,432,902,008,176,640,000)组合,如果您尝试将每个组合简单地存储为位字段中的1位,则需要276,589TB的存储空间。

你将不得不限制你想要做的事情的范围。

答案 2 :(得分:3)

需要多快?

你总是可以将整数收集为一个字符串,然后获取它的散列,然后只抓取前4个字节。

对于哈希,您可以使用任何功能,例如MD5或SHA-256。

答案 3 :(得分:3)

正如其他人所建议的那样,您可以使用散列生成一个具有高概率的唯一整数。但是,如果您需要整数始终是唯一的,则应排序排列,即为它们分配顺序。例如,集合{1,2,3}的常见排列顺序是词典顺序:

  1. 1,2,3
  2. 1,3,2
  3. -2,1,3-
  4. 2,3,1-
  5. 3,1,2
  6. 3,2,1
  7. 在这种情况下,排列的id是字典顺序中的索引。当然,还有其他排列排列的方法。

    使ids成为一系列连续整数,可以将处理后的排列存储为位字段或布尔数组。

答案 4 :(得分:2)

你可以用MD5哈希一个包含你的整数的逗号分隔字符串。

在C#中看起来像这样(免责声明:我今天使用的机器上没有编译器):

using System;
using System.Security.Cryptography;
using System.Text;

public class SomeClass {
    static Guid GetHash(int[] numbers) {
        string csv = string.Join(',', numbers);
        return new Guid(new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(csv.Trim())));
    }
}

编辑:我在想什么?如其他人所述,您不需要哈希。 CSV应该足够作为字符串Id(除非您的数字数组很大)。

答案 5 :(得分:0)

将每个数字转换为String,连接字符串(通过StringBuffer)并将StringBuffer的内容作为键。

答案 6 :(得分:0)

不直接与问题相关,但作为替代解决方案,您可以使用Trie tree作为查找结构。 Trie树非常适合字符串操作,它的实现相对容易,并且它应该比大量长字符串的hashset更快(n(k)的最大值,其中k是键的长度)。并且您不限制密钥大小(例如,必须为int的常规哈希集,而不是更大)。在你的情况下,键将是由一些char分隔的所有数字的字符串。

答案 7 :(得分:0)

Prime power会起作用:如果p_i是i th prime并且a_i是你元组的i th 元素,那么< / p>

p_0**a_0 * p_1**a_1 * ... * p_n**a_n

Fundamental Theorem of Arithmetic应该是唯一的。不过,这些数字会变得很大: - )

(例如,对于n = 5,(1,2,3,4,5)将映射到870,037,764,750,这已经超过32位)

答案 8 :(得分:0)

Bojan's post类似,似乎最好的方法是对排列有一个确定性的顺序。如果按顺序处理它们,则无需进行查找以查看是否已经进行了任何特定的排列。

答案 9 :(得分:0)

获得相同系列数字{1,..,n}的两个排列,构造映射tupple,(id,permutation1 [id],permutation2 [id])或(id,f1(id),f2( ID));您将通过{f3(id)|获得一张独特的地图对于元组(id,f1(id),f2(id)),从id,我们得到一个f2(id),并从元组中找到一个id'(id',f1(id'),f2(id'))其中f1(id')== f2(id)}