web-dev-qa-db-ja.com

文字列のハッシュ関数

現在、クラスでハッシュ関数を扱っています。インストラクターは、コードで使用した2つと比較するために、インターネット上のハッシュ関数を要求しました。

最初の1つ:

int HashTable::hash (string Word)   
// POST: the index of entry is returned
{       int sum = 0;
        for (int k = 0; k < Word.length(); k++)
            sum = sum + int(Word[k]);
        return  sum % SIZE; 
}

第二:

int HashTable::hash (string Word)
{
   int seed = 131; 
   unsigned long hash = 0;
   for(int i = 0; i < Word.length(); i++)
   {
      hash = (hash * seed) + Word[i];
   }
   return hash % SIZE;
}

SIZEは501(ハッシュテーブルのサイズ)で、入力は20,000以上の単語のテキストファイルからのものです。

this いくつかのコード例を含む質問を見ましたが、ハッシュ関数で何を探すべきか正確にはわかりませんでした。正しく理解していれば、私の場合、ハッシュは入力(文字列)を受け取り、文字列に数字を割り当ててテーブルに挿入する数学計算を行います。このプロセスは、リストの検索速度を上げるために行われますか?

私の論理が健全な場合、誰かが文字列を含む異なるハッシュ関数を示す良い例やリソースを持っていますか?または、独自の効率的なハッシュ関数を記述するプロセスです。

22
Nick

まず、通常、実際にはそれほど重要ではありません。ほとんどのハッシュ関数は「十分」です。

しかし、本当に気にするなら、それ自体が研究対象であることを知っておく必要があります。それについては何千もの論文があります。ハッシュアルゴリズムの設計を勉強することで、今日でも博士号を取得できます。

2番目のハッシュ関数は、おそらく文字列"ab"文字列から"ba"。一方、おそらく最初のハッシュ関数よりも高速ではありません。アプリケーションに関連する場合と関連しない場合があります。

ゲノム文字列に使用されるハッシュ関数は、電話データベースの姓をハッシュするのに使用される関数とはまったく異なると思います。おそらく、いくつかの文字列ハッシュ関数でさえ、英語やフランス語の単語よりもドイツ語に適しています。

多くのソフトウェアライブラリは、十分なハッシュ関数を提供します。 Qtには qhash があり、C++ 11には std :: hash in <functional>、Glibには複数の ハッシュ関数 があり、 [〜#〜] poco [〜#〜] には ハッシュ 関数があります。

素数( Bézout's identity を参照)とxorを含むハッシュ関数をよく持っています。

#define A 54059 /* a prime */
#define B 76963 /* another prime */
#define C 86969 /* yet another prime */
#define FIRSTH 37 /* also prime */
unsigned hash_str(const char* s)
{
   unsigned h = FIRSTH;
   while (*s) {
     h = (h * A) ^ (s[0] * B);
     s++;
   }
   return h; // or return h % C;
}

しかし、私はハッシュの専門家であると主張していません。もちろん、ABCFIRSTHの値は素数であることが望ましいですが、他の素数を選択することもできます。

MD5 実装を見て、ハッシュ関数が何であるかを理解してください。

アルゴリズムに関する優れた書籍のほとんどには、少なくともハッシュに関する章全体があります。 ハッシュ関数ハッシュテーブル のwikiページから始めます。

51

-最近の行き方-

SipHash を使用します。あなた自身の保護のため。

-古くて危険な-

unsigned int RSHash(const std::string& str)
{
    unsigned int b    = 378551;
    unsigned int a    = 63689;
    unsigned int hash = 0;

    for(std::size_t i = 0; i < str.length(); i++)
    {
        hash = hash * a + str[i];
        a    = a * b;
    }

    return (hash & 0x7FFFFFFF);
 }

 unsigned int JSHash(const std::string& str)
 {
      unsigned int hash = 1315423911;

      for(std::size_t i = 0; i < str.length(); i++)
      {
          hash ^= ((hash << 5) + str[i] + (hash >> 2));
      }

      return (hash & 0x7FFFFFFF);
 }

「汎用ハッシュ関数」をグーグルに尋ねる

10
esskar

アルゴリズムで使用するハッシュ関数には通常2つの目標があります。1つ目は高速でなければならず、2つ目は、可能な数全体で値を均等に分散させる必要があります。ハッシュ関数は、同じ入力値に対してすべて同じ数を与える必要もありました。

値が文字列の場合、不正なハッシュ関数の例を次に示します。

  1. _string[0]_-ASCII文字a〜Zは他の方法よりも頻繁に使用される
  2. string.lengh()-最も可能性の高い値は1です

優れたハッシュ関数は、計算時間を最小限に抑えながら、入力のすべてのビットを使用しようとします。ハッシュコードのみが必要な場合は、バイトに素数を掛けて合計します。

3
Evan Dark

boost :: hash を使用します

#include <boost\functional\hash.hpp>

...

std::string a = "ABCDE";
size_t b = boost::hash_value(a);
2
Denise Skidmore

Javaの Stringは、このようなhashCodeを実装しています

public int hashCode()

Returns a hash code for this string. The hash code for a String object is computed as

     s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.) 

だからこのようなもの:

int HashTable::hash (string Word) {
    int result = 0;
    for(size_t i = 0; i < Word.length(); ++i) {
        result += Word[i] * pow(31, i);
    }
    return result;
}
1
Brendan Long