我想生成唯一的代码编号(完全由7位数组成)。代码编号随机生成并保存在MySQL表中。
我有另一个要求。所有生成的代码应至少有两位数字不同。这对于在键入用户代码时防止错误很有用。希望它可以防止在执行某些操作时引用另一个用户代码,因为它更不可能错过两个数字并匹配另一个现有的用户代码。
生成算法的工作原理如下:
该算法工作正常,但问题与性能有关。在请求生成大量代码时需要很长时间才能生成代码,例如:10,000。
问题:有没有办法改善此算法的性能?
如果重要的话,我在Ubuntu服务器上使用perl + MySQL。
答案 0 :(得分:10)
您是否考虑过Luhn算法的变体? Luhn用于为许多应用程序(包括信用卡帐号)生成数字串的校验位。它是用于生成标识符的ISO-7812-1标准的一部分。它将捕获使用一个不正确的数字输入的任何数字,这意味着任何两个有效数字至少两位数不同。
在CPAN中查看Algorithm :: LUHN以实现perl实现。
答案 1 :(得分:3)
不要检索现有代码,只需生成一个潜在的新代码,看看数据库中是否存在任何冲突代码:
SELECT code FROM table WHERE abs(code-?) regexp '^[1-9]?0*$';
(占位符是新生成的代码)。
啊,我错过了一次生成大量的代码。这样做(完全未经测试):my @codes = existing_codes();
my $frontwards_index = {};
my $backwards_index = {};
for my $code (@codes) {
index_code($code, $frontwards_index);
index_code(reverse($code), $backwards_index);
}
my @new_codes = map generate_code($frontwards_index, $backwards_index), 1..10000;
sub index_code {
my ($code, $index) = @_;
push @{ $index{ substr($code, 0, length($code)/2) } }, $code;
return;
}
sub check_index {
my ($code, $index) = @_;
my $found = grep { ($_ ^ $code) =~ y/\0//c <= 1 } @{ $index{ substr($code, 0, length($code)/2 } };
return $found;
}
sub generate_code {
my ($frontwards_index, $backwards_index) = @_;
my $new_code;
do {
$new_code = sprintf("%07d", rand(10000000));
} while check_index($new_code, $frontwards_index)
|| check_index(reverse($new_code), $backwards_index);
index_code($new_code, $frontwards_index);
index_code(reverse($new_code), $backwards_index);
return $new_code;
}
答案 2 :(得分:2)
将数字0到9,999,999放在扩充二进制搜索树中。增强是为了跟踪左侧和右侧的子节点数量。因此,例如,当您的算法开始时,顶级节点的值应为5,000,000,并且它应该知道左侧有5,000,000个节点,右侧有4,999,999个节点。现在创建一个哈希表。对于您已经使用过的每个值,从增强二进制搜索树中删除其节点,并将值添加到哈希表中。确保保持增强。
要获得单个值,请按以下步骤操作。
现在,检查值是否可用需要O(1)时间而不是O(n)时间。另外,找到另一个可用的随机值来检查需要O(log n)时间而不是......啊......我不确定如何分析你的算法。
简而言之,如果从头开始并使用此算法,您将在O(n log n)中生成完整的有效代码列表。因为n是10,000,000,所以需要几秒钟或者什么。
我是否在每个人那里做数学计算?如果不检查或者我是否需要澄清任何内容,请告诉我。
答案 3 :(得分:1)
使用哈希。
生成成功的代码(与任何现有代码不冲突),但是哈希表中的代码,并且还将其他63个恰好相差一位的代码放入哈希值。
要查看随机生成的代码是否与现有代码冲突,只需检查哈希中是否存在该代码。
答案 4 :(得分:0)
Howabout:
通过自动增加前一个代码生成一个6位数的代码。 通过递增前一个mod 10生成1位数代码。 连接两者。
Presto,保证两位数不同。 :d
(是的,有点滑稽。我假设'随机'或至少是准随机是必要的。在这种情况下,生成一个6位数的随机密钥,重复直到它不重复(即使列唯一,重复直到插入没有使约束失败),然后生成一个校验位,就像某人已经说过的那样。)