3

さまざまなユーザーが実行したいくつかのテスト結果のファイル指向データベースを作成しています。このために、データベース内のすべてのエントリに対して一意の ID を生成する必要があります。ID は次の要件を満たす必要があります。

  • ID はかなり小さくする必要があります (最大 6 文字)
  • すべてのテストケースとユーザーの組み合わせに対して、毎回同じIDを生成する必要があります

私が試したのは、シード値が 31 の単純な BKDR ハッシュ関数で、次のように ord() 関数を使用しました。

@chars = split(//,$hash_var);

$hash = 0;
$seed = 31;

foreach $char ( @chars ) {
   if( $char !~ m/\d/ ) {
       $hash = ( $seed * $hash ) + ord( $char );
   }  
   else {
       $hash = ( $seed * $hash ) + $char ;
   }
}

$hash = ( $hash & 0x7FFFFFFF ) % 1000;
$hash = "$chars[0]$chars[$#chars]$hash" ;

これにより、さまざまな組み合わせで同じ結果が得られることがあります。つまり、一意性が観察されません。これを達成する他の方法はありますか?シード値を変更すると、一意性を達成するのに役立ちますか?

4

3 に答える 3

5

256 人を超えるユーザーおよび/またはユーザーごとに 65536 を超えるテスト ケースがありますか? そうでない場合は、0 から 255 までのユーザーと 0 から 65535 までのテスト ケースのインデックスを作成し、6 文字で十分な 16 進数の文字列としてエンコードすることができます。

それよりも多くのユーザーまたはテストケースがある場合は、ユーザーとテストケースに再度インデックスを付けてから、それらを 32 ビット整数に結合します。これは実際には 4 バイトしかかからず、実装は簡単ですが、人間にとっては少し難しくなります。

いずれにせよ、ユーザー名とテスト ケース情報が与えられていることを前提としています。ユーザーとテスト ケースをインデックス番号にマップするために、2 つの関連付けられたハッシュを保持するだけ%usersです。%cases

于 2009-06-30T12:41:19.137 に答える
3

問題の一部は、浮動小数点演算を使用していて、BKDR がほぼ確実に整数演算を必要としていることにあるかもしれません。あなたは言うことでそのバグを修正することができます

my @chars = split(//,$hash_var);

my $hash = 0;
my $seed = 31;

for my $char ( @chars ) {
   use integer;
   if( $char !~ m/\d/ ) {
       $hash = ( $seed * $hash ) + ord( $char );
   }  
   else {
       $hash = ( $seed * $hash ) + $char ;
   }
}

$hash = ( $hash & 0x7FFFFFFF ) % 1000;
$hash = "$chars[0]$chars[$#chars]$hash" ;

役立つかもしれない別の微調整は、最初と最後以外の文字を使用することです. 最初と最後の文字が同じ傾向にある場合、それらはハッシュに一意性を追加しません。

MD5 (Digest::MD5 で利用可能) などのより優れたハッシュ関数を使用して、結果を目的のサイズにトリミングすることもできます。ただし、ハッシュを使用しているということは、衝突の危険性があることを意味します。

于 2009-06-30T12:55:07.297 に答える
1

多くのユーザー/テストケースがない場合は、このような単純なソリューションで十分かもしれません。制限を追加する必要があります(おそらく、整数を格納するときにパックします)。

vinko@parrot:~# more hash.pl
use strict;
use warnings;

my %hash;
my $count = 0;

sub getUniqueId {

        my $_user = shift;
        my $_test = shift;
        my $val;

        my $key = $_user."|".$_test;
        if (defined $hash{$key}) {
                $val = $hash{$key};
        } else {
                $hash{$key} = $count;
                $val = $count;
                $count = $count + 1;
        }
        return $val;
}

my @users = qw{ user1 user2 user3 user4 user5 user3 user5 };
my @testcases = qw{ test1 test2 test3 test1 test1 };

for my $user (@users) {
        for my $test (@testcases) {
                print "$user $test: ".getUniqueId($user,$test)."\n";
        }
}
vinko@parrot:~# perl hash.pl
user1 test1: 0
user1 test2: 1
user1 test3: 2
user1 test1: 0
user1 test1: 0
user2 test1: 3
user2 test2: 4
user2 test3: 5
user2 test1: 3
user2 test1: 3
user3 test1: 6
user3 test2: 7
user3 test3: 8
user3 test1: 6
user3 test1: 6
user4 test1: 9
user4 test2: 10
user4 test3: 11
user4 test1: 9
user4 test1: 9
user5 test1: 12
user5 test2: 13
user5 test3: 14
user5 test1: 12
user5 test1: 12
user3 test1: 6
user3 test2: 7
user3 test3: 8
user3 test1: 6
user3 test1: 6
user5 test1: 12
user5 test2: 13
user5 test3: 14
user5 test1: 12
user5 test1: 12
于 2009-06-30T12:52:29.177 に答える