想象两个正整数A和b,我想把这两个组合成一个整数C。
不可能有其他整数D和E组合成C。 所以把它们和加法运算符结合是不行的。例:30 + 10 = 40 = 40 + 0 = 39 + 1 连接也不管用。例如“31”+“2”= 312 =“3”+“12”
这种组合操作也应该是确定的(总是用相同的输入产生相同的结果),并且应该总是在整数的正侧或负侧产生一个整数。
想象两个正整数A和b,我想把这两个组合成一个整数C。
不可能有其他整数D和E组合成C。 所以把它们和加法运算符结合是不行的。例:30 + 10 = 40 = 40 + 0 = 39 + 1 连接也不管用。例如“31”+“2”= 312 =“3”+“12”
这种组合操作也应该是确定的(总是用相同的输入产生相同的结果),并且应该总是在整数的正侧或负侧产生一个整数。
当前回答
f(a, b) = s(a+b) + a,其中 s(n) = n*(n+1)/2
这是一个函数,它是确定的。 它也是单射的——f映射不同(a,b)对的不同值。你可以证明 它使用的事实是:s(a+b+1)-s(a+b) = a+b+1 <一个。 它返回非常小的值——如果你打算用它来做数组索引,那很好,因为数组不需要很大。 它是缓存友好的——如果两个(a, b)对彼此接近,那么f将彼此接近的数字映射到它们(与其他方法相比)。
我不明白您所说的:
应该总是产生一个整数 不管是积极的还是消极的 整数的边
我如何在这个论坛写(大于),(小于)字符?
其他回答
看看这个:http://en.wikipedia.org/wiki/Pigeonhole_principle。如果A, B, C是同一类型,就不能做。如果A和B是16位整数,而C是32位整数,那么您可以简单地使用移位。
哈希算法的本质是它们不能为每个不同的输入提供唯一的哈希。
正整数的标准数学方法是利用质因数分解的唯一性。
f( x, y ) -> 2^x * 3^y
缺点是,图像往往跨越相当大的整数范围,因此当涉及到在计算机算法中表示映射时,您可能会在为结果选择适当的类型时遇到问题。
你可以修改它来处理负x和负y,通过编码一个5和7次幂项的标志。
e.g.
f( x, y ) -> 2^|x| * 3^|y| * 5^(x<0) * 7^(y<0)
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)。
我提供的替代解决方案的链接很好地描绘了利用空间中的每一个点的函数图。令人惊讶的是,你可以将一对坐标可逆地唯一编码为一个数字!神奇的数字世界!!
假设a是第一个,b是第二个。设p是a+1个质数,q是b+1个质数
然后,如果a<b,结果是pq,如果a>b,结果是2pq。如果a=b,让它是p^2。
你正在寻找一个双射NxN - >n映射。这些是用于例如燕尾。请看这个PDF文件,它介绍了所谓的配对函数。维基百科介绍了一个特定的配对函数,即康托配对函数:
备注:三个
As others have made clear, if you plan to implement a pairing function, you may soon find you need arbitrarily large integers (bignums). If you don't want to make a distinction between the pairs (a, b) and (b, a), then sort a and b before applying the pairing function. Actually I lied. You are looking for a bijective ZxZ -> N mapping. Cantor's function only works on non-negative numbers. This is not a problem however, because it's easy to define a bijection f : Z -> N, like so: f(n) = n * 2 if n >= 0 f(n) = -n * 2 - 1 if n < 0