私は文字列に対して良いハッシュ関数を考えようとしています。そして、私はそれが文字列の最初の5文字のUnicode値を合計するのが良い考えかもしれないと考えていました(それが5を持っていると仮定し、そうでなければそれが終わるところで止める)。それは良い考えでしょうか、それとも悪い考えでしょうか。
私はこれをJavaでやっていますが、それが大きな違いになるとは想像できません。
通常ハッシュは合計をしません、そうでなければstop
とpots
は同じハッシュを持ちます。
そうでなければ家と家は同じハッシュを持つことになるので、あなたは最初のn文字に制限しないでしょう。
通常、ハッシュは値を取り、それに素数を掛けます(固有のハッシュを生成する可能性が高くなります)。そのため、次のようなことができます。
int hash = 7;
for (int i = 0; i < strlen; i++) {
hash = hash*31 + charAt(i);
}
セキュリティ上の問題がある場合は、Java暗号を使用できます。
import Java.security.MessageDigest;
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(stringToEncrypt.getBytes());
String encryptedString = new String(messageDigest.digest());
おそらく String.hashCode() を使うべきです。
本当に自分自身でhashCodeを実装したいのなら:
パフォーマンスを向上させるためにハッシュコードの計算からオブジェクトの重要な部分を除外したくない - Joshua Bloch、Effective Java
最初の5文字だけを使うのは悪い考えです。 URLなどの階層名について考えてみましょう。それらはすべて同じハッシュコードを持つことになります(これらはすべて "http://"で始まるため、ハッシュマップの同じバケットの下に格納され、ひどいパフォーマンスを示します)。
これは、 " Effective Java "のString hashCodeについての戦争物語です。
1.2より前のすべてのリリースで実装されていた文字列ハッシュ関数は、最初の文字から始めて、文字列全体に均等な間隔で最大16文字を調べました。 URLなどの階層名の大規模なコレクションでは、このハッシュ関数はひどい動作を示しました。
あなたがJavaでこれをやっているなら、なぜあなたはそれをやっているのですか?文字列に対して.hashCode()
を呼び出すだけです。
GuavaのHashFunction
( javadoc )は、適切な非暗号強度ハッシュを提供します。
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());
}
これは誰かに役立つかもしれません
// 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;
}
FNV-1 は文字列に対する良いハッシュ関数であると噂されています。
長い文字列(200文字以上など)の場合は、 MD4 ハッシュ関数を使用するとパフォーマンスが向上します。暗号化機能として、それは約15年前に壊れていました、しかし非暗号化目的のために、それはまだ非常によく、そして驚くほど速いです。 Javaのコンテキストでは、16ビットのchar
の値を32ビットの単語に変換する必要があります。そのような値をペアにグループ化することによって。 JavaでのMD4の高速実装は sphlib にあります。教室での割り当ての状況ではおそらくやり過ぎるでしょうが、そうでなければ試してみる価値があります。
業界標準の実装を見たいのであれば、 Java.security.MessageDigest を見てください。
「メッセージダイジェストは、任意のサイズのデータを受け取り、固定長ハッシュ値を出力する安全な一方向ハッシュ関数です。」
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;
}
ここに リンク がありますが、ここではさまざまなハッシュ関数について説明します。今のところ、私はあなたの特定の問題にはELFハッシュ関数を使用します。入力として任意の長さの文字列を取ります。
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();
}
これにより衝突が回避され、シフトを計算に使用するまで高速になります。
int k = key.length();
int sum = 0;
for(int i = 0 ; i < k-1 ; i++){
sum += key.charAt(i)<<(5*i);
}