Хэш-функция для строк

в настоящее время мы имеем дело с хэш-функция в моем классе. Наш инструктор попросил нас хэш-функцию в интернете, чтобы сравнить с двумя, которые мы использовали в нашем коде.

первый:

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;
}

где размер 501 (размер хэш-таблицы), а вход поступает из текстового файла 20,000+ слов.

Я видел этой вопрос с несколькими примерами кода, но не был точно уверен, что искать Для в хэш-функции. Если я правильно понимаю, в моем случае хэш принимает вход (строку) и выполняет математический расчет, чтобы назначить строке число и вставить его в таблицу. Этот процесс делается для увеличения скорости поиска по списку?

Если моя логика звучит, есть ли у кого-нибудь хороший пример или ресурс, показывающий другую хэш-функцию, которая включает строку? Или даже процесс написания моей собственной эффективной хэш-функции.

5 ответов


во-первых, это обычно не имеет большого значения на практике. Большинство хэш-функций "достаточно хороши".

но если вы действительно заботитесь, вы должны знать, что это предмет исследования сам по себе. Об этом есть тысячи газет. Вы все еще можете получить PhD сегодня, изучая и разрабатывая алгоритмы хэширования.

второй Ваш хэш-функция может быть немного лучше, потому что она, вероятно, должна разделить строку "ab" в строке "ba". С другой стороны, это вероятно, менее быстрая, чем первая хэш-функция. Это может иметь или не иметь отношение к вашему заявлению.

Я предполагаю, что хэш-функции, используемые для строк генома, сильно отличаются от тех, которые используются для хэширования фамилий в телефонных базах данных. Возможно, даже некоторые строковые хэш-функции лучше подходят для немецкого языка, чем для английских или французских слов.

многие программные библиотеки дают вам достаточно хорошие хэш-функции, например Qt имеет qhash и C++11 имеет std:: hash на <functional>, Glib имеет несколько хэш-функции в C, и поко некоторые хэшBézout по) и 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;
}

но я не претендую на то, чтобы быть экспертом по хэшу. Конечно, значения A, B, C, FIRSTH предпочтительно должны быть простые числа, но вы могли бы выбрать другое простое число числа.

смотреть на некоторые MD5 в реализация, чтобы получить представление о том, какие хэш-функции могут быть.

большинство хороших книг по алгоритмике имеют по крайней мере целую главу, посвященную хешированию. Начните с wikipages on хэш-функция & хэш-таблицы.


-- путь в эти дни --

использовать 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);
 }

спросите google для "хэш-функции общего назначения"


хэш-функции для алгоритмического использования обычно имеют 2 цели, во-первых, они должны быть быстрыми, во-вторых, они должны равномерно распределять значения по возможным числам. Хэш-функция также должна давать одинаковое число для одного и того же входного значения.

Если ваши значения являются строками, вот несколько примеров для плохих хэш-функций:

  1. string[0] - символы ASCII a-Z чаще, чем другие
  2. string.lengh() - наиболее вероятное значение 1

хорошие хэш-функции пытаются использовать каждый бит ввода, сохраняя при этом минимальное время вычисления. Если вам нужен только хэш-код, попробуйте умножить байты на простые числа и суммировать их.


использовать boost:: hash

#include <boost\functional\hash.hpp>

...

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

в Java String реализует хэш-код такой:

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;
}