我有一个可以递增增加id的数据库。我需要一个函数将该id转换为0到1000之间的唯一数字。(实际的最大值要大得多,但为了简单起见。)
1 => 3301,
2 => 0234,
3 => 7928,
4 => 9821
生成的数字不能重复。 它不能是增量的。 需要它在运行中生成(不创建一个统一数字表来读取)
我认为是哈希函数,但存在冲突的可能性。 随机数也可能有重复数。 我需要一个最小的完美哈希函数,但找不到简单的解决方案。
答案 0 :(得分:1)
由于标准有点模糊(足以欺骗普通人),我不确定要采取哪条路线。以下是一些想法:
您可以使用Pearson hash。根据维基百科页面:
给定一组小的特权输入(例如,编译器的保留字),可以调整置换表,以便这些输入产生不同的散列值,产生所谓的完美散列函数。
您可以使用复杂的一对一数学函数。这样做的缺点是,由于一对一的要求,很难制造一个没有严格增加或严格减少的产品。如果你做了类似(id ^ 2) + id * 2
之类的事情,那么ids之间的间隔会发生变化,如果不知道原始ID,这个函数就不会立即明显。
你可以这样做:
new_id = (old_id << 4) + arbitrary_4bit_hash(old_id);
这将给出唯一的ID,并且不会立即明显前4位只是垃圾(特别是在读取十进制格式的数字时)。与最后一个选项一样,新ID的顺序与旧ID相同。我不知道这是不是一个问题。
您可以通过使查找数组中包含“随机”数字来对所有ID转换进行硬编码。
您可以使用某种哈希函数生成器,如gperf。
GNU gperf是一个完美的哈希函数生成器。对于给定的字符串列表,它以C或C ++代码的形式生成散列函数和散列表,用于根据输入字符串查找值。散列函数是完美的,这意味着散列表没有冲突,并且散列表查找只需要单个字符串比较。
您可以使用加密安全机制使用密钥加密ID。
希望其中一个适合你。
<强>更新强>
这是OP要求的轮换班次:
function map($number)
{
// Shift the high bits down to the low end and the low bits
// down to the high end
// Also, mask out all but 10 bits. This allows unique mappings
// from 0-1023 to 0-1023
$high_bits = 0b0000001111111000 & $number;
$new_low_bits = $high_bits >> 3;
$low_bits = 0b0000000000000111 & $number;
$new_high_bits = $low_bits << 7;
// Recombine bits
$new_number = $new_high_bits | $new_low_bits;
return $new_number;
}
function demap($number)
{
// Shift the high bits down to the low end and the low bits
// down to the high end
$high_bits = 0b0000001110000000 & $number;
$new_low_bits = $high_bits >> 7;
$low_bits = 0b0000000001111111 & $number;
$new_high_bits = $low_bits << 3;
// Recombine bits
$new_number = $new_high_bits | $new_low_bits;
return $new_number;
}
这种方法有其优点和缺点。我能想到的主要缺点(除了安全方面)是对于较低的ID,连续数字将完全相同(乘法)间隔,直到数字开始环绕。也就是说
map(1) * 2 == map(2)
map(1) * 3 == map(3)
当然,这种情况会发生,因为数字越小,所有高位都为0,因此map函数等效于仅移位。这就是为什么我建议将伪随机数据用于较低位而不是数字的较高位。它会使常规间隔不那么明显。为了帮助缓解这个问题,我编写的函数只移动前3位并旋转其余部分。通过这样做,对于大于7的所有ID,常规间隔将不太明显。
答案 1 :(得分:0)
似乎它不是必须数字? MD5-Hash怎么样?
从......
中选择md5(id + rand(10000))