値をハッシュしようとしています
10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0
衝突を起こさずにサイズ13の配列にマップする関数が必要です。
私はこれを考えてグーグルで数時間を費やしましたが、これを理解することはできません。私は実行可能な解決策に近づいていません。
この種のハッシュ関数を見つけるにはどうすればよいですか?gperfで遊んだことがありますが、よくわからず、探していた結果が得られませんでした。
値をハッシュしようとしています
10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0
衝突を起こさずにサイズ13の配列にマップする関数が必要です。
私はこれを考えてグーグルで数時間を費やしましたが、これを理解することはできません。私は実行可能な解決策に近づいていません。
この種のハッシュ関数を見つけるにはどうすればよいですか?gperfで遊んだことがありますが、よくわからず、探していた結果が得られませんでした。
正確なキーがわかっている場合は、完全なハッシュ関数を作成するのは簡単です-
int hash (int n) {
switch (n) {
case 10: return 0;
case 100: return 1;
case 32: return 2;
// ...
default: return -1;
}
}
私はいくつかのことを試し、半手動で見つけました:
(n ^ 28) % 13
半手動の部分は、さまざまなパラメーターを使用して候補関数をテストするために使用した次のルビースクリプトでした。
t = [10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0]
(1..200).each do |i|
t2 = t.map { |e| (e ^ i) % 13 }
puts i if t2.uniq.length == t.length
end
一部のプラットフォーム(組み込みなど)では、モジュロ演算はコストがかかるため、% 13
回避することをお勧めします。ただしAND
、下位ビットの演算は安価であり、2の累乗のモジュロと同等です。
11個のデータポイントの完全なハッシュを検索するための簡単なプログラム(Pythonで)を作成してみました。たとえば、((x << a) ^ (x << b)) & 0xF
(は、& 0xF
と同等で% 16
、結果は0..15の範囲になります)などの簡単な形式を使用します。0..15の範囲のインデックス(Cマクロとして表される)を与える次の衝突のないハッシュを見つけることができました:
#define HASH(x) ((((x) << 2) ^ ((x) >> 2)) & 0xF)
これが私が使用したPythonプログラムです:
data = [ 10, 100, 32, 45, 58, 126, 3, 29, 200, 400, 0 ]
def shift_right(value, shift_value):
"""Shift right that allows for negative values, which shift left
(Python shift operator doesn't allow negative shift values)"""
if shift_value == None:
return 0
if shift_value < 0:
return value << (-shift_value)
else:
return value >> shift_value
def find_hash():
def hashf(val, i, j = None, k = None):
return (shift_right(val, i) ^ shift_right(val, j) ^ shift_right(val, k)) & 0xF
for i in xrange(-7, 8):
for j in xrange(i, 8):
#for k in xrange(j, 8):
#j = None
k = None
outputs = set()
for val in data:
hash_val = hashf(val, i, j, k)
if hash_val >= 13:
pass
#break
if hash_val in outputs:
break
else:
outputs.add(hash_val)
else:
print i, j, k, outputs
if __name__ == '__main__':
find_hash()
いくつかの準分析的なとりとめのないもの:
あなたの数のセットでは、全部で11、3は奇数、8は偶数です。最も単純な形式のハッシュ(%13)を見ると、次のハッシュ値が得られます:10-3、100-9、32-6、45-6、58-6、126-9、3-3、29-3 、200-5、400-10、0-0
もちろん、これは衝突の数のために使用できません。もっと手の込んだものが必要です。
なぜ明白なことを述べるのですか?数が非常に少ないことを考えると、複雑な(つまり「単純ではない」)アルゴリズムは、switchステートメントまたは(私が好む)サイズ11の位置の符号なしの短い/長いベクトルを検索して、一致のインデックス。
なぜベクトル検索を使用するのですか?
ボブ・ジェンキンスにもこのためのプログラムがあります:http: //burtleburtle.net/bob/hash/perfect.html
運が良ければ、特定のデータセットに「優れた」完璧なハッシュ関数はありません。完全なハッシュアルゴリズムは通常、キーに対して単純なハッシュ関数を使用し(十分なビットを使用して衝突がないようにします)、テーブルを使用してそれを終了します。
簡単なチェックをしてSHA256ハッシュ関数を使ってから、Mathematicaで試してみたところ、13によるモジュラー除算がうまくいきました。C ++の場合、この関数はopensslライブラリにある必要があります。この投稿を参照してください。
ただし、多くのハッシュとルックアップを実行している場合、モジュラー除算は繰り返し実行するにはかなりコストのかかる操作です。nビットのハッシュ関数をiビットのインデックスにマッピングする別の方法があります。Cでビットシフト操作を使用してそれを行う方法については、MichaelMitzenmacherによるこの投稿を参照してください。お役に立てば幸いです。
n値を0から12までの一意のインデックスにマップする次のことを試してください(1369%(n + 1))%13