我正在尝试实现一对值的存储。它必须公开一个简单的API:newPair, get, remove, isMember
。值可以包含4-bit int
或指向另一对的指针。所以,例如:
Pointer a = API.newPair(13,12);
Pointer b = API.newPair(a,7);
Pointer c = API.newPair(2,b);
Pointer d = API.newPair(a,7);
等等。但是,只有一个警告:一对不能存储两次。如果您尝试添加已存在的对,它只返回现有指针。因此,例如,在上面的代码中,b == d
。
我天真的实现涉及一堆对。每次添加一对新对时,我只是迭代堆栈,如果我找到了那对,我就返回它的位置。如果没有,我向堆栈添加了一个新元素并返回了堆栈大小。现在我需要尽可能快地完成它。我目前的想法是只使用哈希表而不是堆栈。
所以,问题是:实现这个的快速方法是什么?
答案 0 :(得分:3)
双射NxN - >由Cantor Pairing Function
给出的N.
。它通过以这种方式连续将NxN的元素分配给N来工作:
当x,y为非负整数时,可以使用ElegantPairing中引入的映射
x >= y ? x * x + x + y : x + y * y; where x, y >= 0
通过沿着squere的边缘分配值来工作。
int cantor_pairing( int k1, int k2) {
return 0.5 * ( k1 + k2) * ( k1 + k2 + 1) + k2;
}
int szuzik_pairing( int x, int y) {
if( x < 0 || y < 0) return -1;
return x >= y ? x * x + x + y : x + y * y;
}
即使你的整数是统一分布的,你也不能只使用映射
(x,y) - &gt; X
即。完全无视第二个。这是因为在正方形上NxN f(x,y)将是1 / N ^ 2但是边际分布f_y(x)= 1 / N并且这将是碰撞的概率。 毕竟,很可能情况并非如此,因为用户会更频繁地选择小数字然后大。
答案 1 :(得分:1)
如果您的对具有4位元素,则char(在99%的情况下= 8位长)足以存储一对。一点注释:对于一个4位长(带符号)整数,你允许的值范围是:[ - 7,8],但是,在你的例子中,你已经使用了值12和13,所以,我理解你的对由两个4位无符号整数组成。
// a and b should be values between 0 and 15.
// Otherwise, the behaviour is undefined
// (or if you want, you could control the values of
// a/b and throw an exception in the opposite case).
Pair APIClass::newPair(unsigned a, unsigned b)
{
char c = (char(a) << 4) | char(b);
return Pair(c); // `typedef char Pair;` p.e.
}
假设unsigned
s a
和b
介于0到15之间,则为二进制:
a ≡ 0000000000000000000000000000xxxx // 32-bits
b ≡ 0000000000000000000000000000yyyy // 32-bits
目标是:
Pair ≡ xxxxyyyy // 8-bits
因此,发生以下转换:
// For a
0000000000000000000000000000xxxx => conversion to char
0000xxxx => 4-bits left-shift
xxxx0000
// For b
0000000000000000000000000000yyyy => conversion to char
0000yyyy
// Result:
xxxx0000
| 0000yyyy
--------------
xxxxyyyy
那就是全部。
最后,如果你的意思是4字节int
s,同样的推理适用但使用long long int
作为占位符(尽管不是在每个架构中long long int
都是64位长)。