字符串的哈希函数不考虑char的位置

时间:2015-01-15 19:04:05

标签: algorithm hash hashtable

我的问题的标题是自我描述性的。 我需要哈希一个三个64位变量的结构(我将它们转换成一串字符),每个变量包含一手牌 - 纸牌游戏应用程序,因此在这些变量中交换一些字符应该产生相同的哈希值。 一种方法是对结果字符串进行排序。有没有更好的解决方案?

2 个答案:

答案 0 :(得分:1)

如果手的表示类似于位集,则它已经是无序的。例如,如果您使用位掩码的组合来表示卡片的组合,例如,像这样

A♠ - 0x00000001
2♠ - 0x00000002
3♠ - 0x00000004
4♠ - 0x00000008
...
K♠ - 0x00001000
A♥ - 0x00002000
2♥ - 0x00004000
...

然后您可以使用位组合来表示手,如下所示:

A♠ 4♠ 2♥ - 0x00004009

此表示与位置无关,即指针4♠ A♠ 2♥2♥ 4♠ A♠A♠ 4♠ 2♥具有完全相同的表示形式。您可以根据需要通过迭代各个位将此表示转换为字符串,并在每次发现设置为1的位时将卡添加到字符串表示中。

这样的表示可以用于通过将表示的高32位与低32位进行异或来计算32位哈希码:

uint64_t hand = ... // A representation of hand similar to what's described above
uint32_t hash = (uint32_t)(hand ^ (hand >> 32));
  

目前我的卡片以字节形式显示,但两张卡片中的位可以重叠:A♣ = 0x11; 10♣=0x12; K♣=0x13 ...依此类推。

您可以在计算哈希码时将此表示转换为上述表示,并避免以这种方式排序:

// Each card is a number from 1 to 53, inclusive
uint8_t hand[HAND_SIZE] = ...; // The hand
uint64_t set = 0;
for (int i = 0 ; i != HAND_SIZE ; i++) {
    set |= (1LL << hand[i]);
}
uint32_t hash = (uint32_t)(set ^ (set >> 32));

答案 1 :(得分:0)

另一种方法是计算每个字符的出现次数,然后对结果向量进行散列(向量count,其中count[c]是字符出现的次数{{ 1}})。我不会说它比排序更好(字符数是固定的(可能相当低)所以你可以使用基数排序)(但我不能说它也更糟)。两者的时间复杂度:使用基数排序进行排序和计算每个字符的出现次数是线性的(此外,基数排序和计数字符几乎是相同的),因此这两者之间不应该有很大差异。