web-dev-qa-db-ja.com

文字列に対するグッドハッシュ関数

私は文字列に対して良いハッシュ関数を考えようとしています。そして、私はそれが文字列の最初の5文字のUnicode値を合計するのが良い考えかもしれないと考えていました(それが5を持っていると仮定し、そうでなければそれが終わるところで止める)。それは良い考えでしょうか、それとも悪い考えでしょうか。

私はこれをJavaでやっていますが、それが大きな違いになるとは想像できません。

141
Leif Andersen

通常ハッシュは合計をしません、そうでなければstoppotsは同じハッシュを持ちます。

そうでなければ家と家は同じハッシュを持つことになるので、あなたは最初のn文字に制限しないでしょう。

通常、ハッシュは値を取り、それに素数を掛けます(固有のハッシュを生成する可能性が高くなります)。そのため、次のようなことができます。

int hash = 7;
for (int i = 0; i < strlen; i++) {
    hash = hash*31 + charAt(i);
}
143
jonathanasdf

セキュリティ上の問題がある場合は、Java暗号を使用できます。

import Java.security.MessageDigest;

MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(stringToEncrypt.getBytes());
String encryptedString = new String(messageDigest.digest());
128
Nick

おそらく String.hashCode() を使うべきです。

本当に自分自身でhashCodeを実装したいのなら:

パフォーマンスを向上させるためにハッシュコードの計算からオブジェクトの重要な部分を除外したくない - Joshua Bloch、Effective Java

最初の5文字だけを使うのは悪い考えです。 URLなどの階層名について考えてみましょう。それらはすべて同じハッシュコードを持つことになります(これらはすべて "http://"で始まるため、ハッシュマップの同じバケットの下に格納され、ひどいパフォーマンスを示します)。

これは、 " Effective Java "のString hashCodeについての戦争物語です。

1.2より前のすべてのリリースで実装されていた文字列ハッシュ関数は、最初の文字から始めて、文字列全体に均等な間隔で最大16文字を調べました。 URLなどの階層名の大規模なコレクションでは、このハッシュ関数はひどい動作を示しました。

36
Frederik

あなたがJavaでこれをやっているなら、なぜあなたはそれをやっているのですか?文字列に対して.hashCode()を呼び出すだけです。

17
Pyrolistical

GuavaのHashFunctionjavadoc )は、適切な非暗号強度ハッシュを提供します。

12
Mike Samuel

Nickが提供するこの関数は優れていますが、新しいString(byte [] bytes)を使ってStringに変換すると失敗しました。あなたはそれをするためにこの関数を使うことができます。

private static final char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

public static String byteArray2Hex(byte[] bytes) {
    StringBuffer sb = new StringBuffer(bytes.length * 2);
    for(final byte b : bytes) {
        sb.append(hex[(b & 0xF0) >> 4]);
        sb.append(hex[b & 0x0F]);
    }
    return sb.toString();
}

public static String getStringFromSHA256(String stringToEncrypt) throws NoSuchAlgorithmException {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
    messageDigest.update(stringToEncrypt.getBytes());
    return byteArray2Hex(messageDigest.digest());
}

これは誰かに役立つかもしれません

7
Festus Tamakloe
// djb2 hash function
unsigned long hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

ソースdjb2ハッシュ関数の背後にあるロジック - SO

5
Pratik Deoghare

FNV-1 は文字列に対する良いハッシュ関数であると噂されています。

長い文字列(200文字以上など)の場合は、 MD4 ハッシュ関数を使用するとパフォーマンスが向上します。暗号化機能として、それは約15年前に壊れていました、しかし非暗号化目的のために、それはまだ非常によく、そして驚くほど速いです。 Javaのコンテキストでは、16ビットのcharの値を32ビットの単語に変換する必要があります。そのような値をペアにグループ化することによって。 JavaでのMD4の高速実装は sphlib にあります。教室での割り当ての状況ではおそらくやり過ぎるでしょうが、そうでなければ試してみる価値があります。

4
Thomas Pornin

業界標準の実装を見たいのであれば、 Java.security.MessageDigest を見てください。

「メッセージダイジェストは、任意のサイズのデータ​​を受け取り、固定長ハッシュ値を出力する安全な一方向ハッシュ関数です。」

3
Dean J

sdbm:このアルゴリズムは、sdbm(ndbmのパブリックドメイン再実装)データベースライブラリ用に作成されました。

static unsigned long sdbm(unsigned char *str)
{   
    unsigned long hash = 0;
    int c;
    while (c = *str++)
            hash = c + (hash << 6) + (hash << 16) - hash;

    return hash;
}
2
Anchal

ここに リンク がありますが、ここではさまざまなハッシュ関数について説明します。今のところ、私はあなたの特定の問題にはELFハッシュ関数を使用します。入力として任意の長さの文字列を取ります。

1
Yefei
         public String hashString(String s) throws NoSuchAlgorithmException {
    byte[] hash = null;
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        hash = md.digest(s.getBytes());

    } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < hash.length; ++i) {
        String hex = Integer.toHexString(hash[i]);
        if (hex.length() == 1) {
            sb.append(0);
            sb.append(hex.charAt(hex.length() - 1));
        } else {
            sb.append(hex.substring(hex.length() - 2));
        }
    }
    return sb.toString();
}
0
Charaf JRA

これにより衝突が回避され、シフトを計算に使用するまで高速になります。

 int k = key.length();
    int sum = 0;
    for(int i = 0 ; i < k-1 ; i++){
        sum += key.charAt(i)<<(5*i);
    }
0