想象两个正整数A和b,我想把这两个组合成一个整数C。

不可能有其他整数D和E组合成C。 所以把它们和加法运算符结合是不行的。例:30 + 10 = 40 = 40 + 0 = 39 + 1 连接也不管用。例如“31”+“2”= 312 =“3”+“12”

这种组合操作也应该是确定的(总是用相同的输入产生相同的结果),并且应该总是在整数的正侧或负侧产生一个整数。


当前回答

看看这个:http://en.wikipedia.org/wiki/Pigeonhole_principle。如果A, B, C是同一类型,就不能做。如果A和B是16位整数,而C是32位整数,那么您可以简单地使用移位。

哈希算法的本质是它们不能为每个不同的输入提供唯一的哈希。

其他回答

再简单一点:给定两个数字,A和B让str为串联:'A' + ';' + 'B'。然后让输出为hash(str)。我知道这不是一个数学答案,但一个简单的python(有一个内置的哈希函数)脚本应该做这项工作。

Cantor pairing function is really one of the better ones out there considering its simple, fast and space efficient, but there is something even better published at Wolfram by Matthew Szudzik, here. The limitation of Cantor pairing function (relatively) is that the range of encoded results doesn't always stay within the limits of a 2N bit integer if the inputs are two N bit integers. That is, if my inputs are two 16 bit integers ranging from 0 to 2^16 -1, then there are 2^16 * (2^16 -1) combinations of inputs possible, so by the obvious Pigeonhole Principle, we need an output of size at least 2^16 * (2^16 -1), which is equal to 2^32 - 2^16, or in other words, a map of 32 bit numbers should be feasible ideally. This may not be of little practical importance in programming world.

康托配对函数:

(a + b) * (a + b + 1) / 2 + a; where a, b >= 0

两个最大最多16位整数(65535,65535)的映射将是8589803520,正如您所看到的,它不能适合32位。

进入Szudzik函数:

a >= b ? a * a + a + b : a + b * b;  where a, b >= 0

(65535, 65535)的映射现在将是4294967295,正如您所看到的,这是一个32位(0到2^32 -1)整数。这就是这个解决方案的理想之处,它只是利用了空间中的每一个点,所以没有什么比空间效率更高了。


现在考虑到我们通常在语言/框架中处理各种大小的数字的有符号实现,让我们考虑从-(2^15)到2^15 -1的有符号16位整数(稍后我们将看到如何扩展输出以跨越有符号范围)。因为a和b必须是正的它们的取值范围是0到2^15 - 1。

康托配对函数:

两个最大最多的16位有符号整数(32767,32767)的映射将是2147418112,这恰好小于32位有符号整数的最大值。

现在是Szudzik函数:

(32767, 32767) => 1073741823, many small ..

让我们考虑负整数。我知道这超出了最初的问题,但只是详细说明,以帮助未来的游客。

康托配对函数:

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
(A + B) * (A + B + 1) / 2 + A;

(-32768, -32768) => 8589803520,即Int64。64位输出的16位输入可能是如此不可原谅!!

Szudzik的函数:

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
A >= B ? A * A + A + B : A + B * B;

(-32768, -32768) => 4294967295,对于无符号范围是32位,对于有符号范围是64位,但仍然更好。

现在所有这些输出都是正的。在有符号的世界中,如果我们能将输出的一半转移到负轴上,将会更加节省空间。对于Szudzik's,你可以这样做:

A = a >= 0 ? 2 * a : -2 * a - 1;
B = b >= 0 ? 2 * b : -2 * b - 1;
C = (A >= B ? A * A + A + B : A + B * B) / 2;
a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;

(-32768, 32767) => -2147483648

(32767, -32768) => -2147450880

(0, 0) => 0 

(32767, 32767) => 2147418112

(-32768, -32768) => 2147483647

我所做的:在对输入施加2的权重并遍历函数后,然后将输出除以2,并通过乘以-1将其中一些输出移到负轴。

看看结果,对于任何有符号的16位数字范围内的输入,输出都在有符号的32位整数的范围内,这很酷。我不确定如何对康托配对函数进行同样的处理,但没有尝试那么多,因为它不那么有效。此外,康托配对函数涉及的计算量更多,也意味着它的速度更慢。

下面是一个c#实现。

public static long PerfectlyHashThem(int a, int b)
{
    var A = (ulong)(a >= 0 ? 2 * (long)a : -2 * (long)a - 1);
    var B = (ulong)(b >= 0 ? 2 * (long)b : -2 * (long)b - 1);
    var C = (long)((A >= B ? A * A + A + B : A + B * B) / 2);
    return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}

public static int PerfectlyHashThem(short a, short b)
{
    var A = (uint)(a >= 0 ? 2 * a : -2 * a - 1);
    var B = (uint)(b >= 0 ? 2 * b : -2 * b - 1);
    var C = (int)((A >= B ? A * A + A + B : A + B * B) / 2);
    return a < 0 && b < 0 || a >= 0 && b >= 0 ? C : -C - 1;
}

由于中间计算可能会超过2N有符号整数的限制,所以我使用了4N整数类型(最后除以2将结果带回2N)。

我提供的替代解决方案的链接很好地描绘了利用空间中的每一个点的函数图。令人惊讶的是,你可以将一对坐标可逆地唯一编码为一个数字!神奇的数字世界!!

尽管Stephan202的答案是唯一真正通用的答案,但对于有限范围内的整数,您可以做得更好。例如,如果你的范围是0..1万,那么你可以这样做:

#define RANGE_MIN 0
#define RANGE_MAX 10000

unsigned int merge(unsigned int x, unsigned int y)
{
    return (x * (RANGE_MAX - RANGE_MIN + 1)) + y;
}

void split(unsigned int v, unsigned int &x, unsigned int &y)
{
    x = RANGE_MIN + (v / (RANGE_MAX - RANGE_MIN + 1));
    y = RANGE_MIN + (v % (RANGE_MAX - RANGE_MIN + 1));
}

结果可以适用于单个整数,其范围可达整数类型基数的平方根。这种打包方法比Stephan202更通用的方法效率稍高。它的解码也简单得多;对于初学者来说,不需要平方根:)

看看这个:http://en.wikipedia.org/wiki/Pigeonhole_principle。如果A, B, C是同一类型,就不能做。如果A和B是16位整数,而C是32位整数,那么您可以简单地使用移位。

哈希算法的本质是它们不能为每个不同的输入提供唯一的哈希。

假设a是第一个,b是第二个。设p是a+1个质数,q是b+1个质数

然后,如果a<b,结果是pq,如果a>b,结果是2pq。如果a=b,让它是p^2。