Как я могу хэшировать строку в int с помощью c++?

Я должен написать свою собственную хэш-функцию. Если бы я хотел просто сделать простую хэш-функцию, которая сопоставляет каждую букву в строке с числовым значением (т. е. a=1, b=2, c=3, ...), есть ли способ выполнить этот хэш на строке без необходимости сначала преобразовать его в C-строку, чтобы посмотреть на каждый отдельный символ? Есть ли более эффективный способ хэширования строк?

9 ответов


Re первый вопрос, конечно, e.g, что-то вроде:

int hash = 0;
int offset = 'a' - 1;
for(string::const_iterator it=s.begin(); it!=s.end(); ++it) {
  hash = hash << 1 | (*it - offset);
}

что касается второго, есть много лучших способов хэширования строк. Е. Г., вижу здесь для нескольких примеров C (легко переводимых на C++ вдоль строк фрагмента выше).


из личного опыта я знаю, что это работает и дает хорошие дистрибутивы. (Заимствованы из http://www.cse.yorku.ca/~oz/hash.html):

djb2

этот алгоритм (k=33) впервые был сообщен Дэном Бернштейном много лет назад в comp.ленг.c. другая версия этого алгоритма (теперь любимая Бернштейном) использует xor: hash(i) = hash (i - 1) * 33 ^ str[i]; магия числа 33 (почему она работает лучше, чем многие другие константы, простые или нет) никогда не была было адекватно объяснено.

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

вы можете изучить каждый отдельный символ из строки std::, используя [] оператора. Тем не менее, вы можете посмотреть на Boost:: Functional/Hash для руководства по лучшей схеме хэширования. Существует также список функций хэширования в C located здесь.


вот хэш-функция C ( ++ ), которую я нашел в книге Страуструпа:

int hash(const char *str)
{
    int h = 0;
    while (*str)
       h = h << 1 ^ *str++;
    return h;
}

Если вы используете его для хэш-таблицы (что делает Stroustrup), то вы можете вместо этого вернуть abs хэш-модуля простое число. Так что вместо этого

    return (h > 0 ? h : -h) % N_BUCKETS;

на последней строке.


C++11 поставляется со стандартной функцией хэширования для строк.

https://en.cppreference.com/w/cpp/string/basic_string/hash

#include <string>
#include<functional> // hash
int main(){
    std::string s = "Hello";
    std::size_t hash = std::hash<std::string>{}(s);
}

xor символы вместе, по четыре за раз.


#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

// a variation on dan bernstein's algorithm
// [http://www.cse.yorku.ca/~oz/hash.html]
template<typename Int>
struct hash {
    hash() : acc(5381) { }
    template<typename Ch>
    void operator()(Ch ch) { acc = ((acc << 5) + acc) ^ ch; }
    operator Int() const { return acc; }
    Int acc;
};

int main(int argc, char* argv[])
{
    string s("Hellp, world");
    cout << hex << showbase
        << for_each(s.begin(), s.end(), hash<unsigned long long>()) << '\n';
    return 0;
}

другой способ для небольших строк:

int hash(const char* str) {
    int hash = 0;
    int c = 0;

    while (c < std::strlen(str)) {
        hash += (int)str[c] << (int)str[c+1];
        c++;
    }
    return hash;
}

вы можете использовать функции-члены оператор[] или at класса string или итераторов для доступа к отдельному символу строкового объекта без преобразования его в массив символов c-стиля.

чтобы хэшировать строковый объект в целое число, вам нужно будет получить доступ к каждому отдельному символу строкового объекта, который вы можете сделать как:

for (i=0; i < str.length(); i++) {
    // use str[i] or str.at(i) to access ith element.
}