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

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

Я делаю это на Java, но я не думаю, что это будет иметь большое значение.

15 ответов


обычно хэши не будут делать суммы, иначе stop и pots будет иметь тот же самый хэш.

и вы не ограничите его первыми n символами, потому что в противном случае дом и дома будут иметь один и тот же хэш.

обычно хэши принимают значения и умножают их на простое число (что делает его более вероятным для создания уникальных хэшей), чтобы вы могли сделать что-то вроде:

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

Если это вещь безопасности, вы можете использовать Java crypto:

import java.security.MessageDigest;

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

вы, вероятно, должны использовать строку.hashCode ().

Если вы действительно хотите реализовать себя хэш-кода:

Не поддавайтесь искушению исключить значительные части объекта от вычисление хэш-кода для улучшения производительность -- Joshua Bloch, эффективная Java

использование только первых пяти символов-это плохая идея. Подумайте об иерархических именах, таких как URL-адреса: все они будут иметь один и тот же хэш-код (потому что все они начинаются с " http://", что означает, что они хранятся в одном ведре в хэш-карте, демонстрируя ужасную производительность.

вот история войны, перефразированная на строковый хэш-код из "Эффективная Java":

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


Если вы делаете это на Java, то почему вы это делаете? Просто позвони .hashCode() в строке


гуава это HashFunction (javadoc) обеспечивает достойное не крипто-сильное хеширование.


эта функция, предоставленная ником, хороша, но если вы используете новую строку (байт[] байт) для преобразования в строку, это не удалось. Для этого можно использовать эту функцию.

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

источник логика за хэш-функцией djb2-SO


Если вы хотите увидеть отраслевые стандартные реализации, я бы посмотрел на java.безопасность.MessageDigest.

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


FNV-1 по слухам, является хорошей хэш-функцией для строк.

для длинных строк (длиннее, чем, скажем, около 200 символов), вы можете получить хорошую производительность из алгоритмов MD4 хэш-функция. Как криптографическая функция, она была сломана около 15 лет назад, но для не криптографических целей она все еще очень хороша и удивительно быстра. В контексте Java вам придется преобразовать 16-битный char значения в 32-битные слова, например, путем группировки таких значения в пары. Быстрая реализация MD4 в Java можно найти в sphlib. Вероятно, излишне в контексте классного задания, но в остальном стоит попробовать.


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

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

int keyHash(string key)
{
    unsigned int k = (int)key.length();
    unsigned int u = 0,n = 0;

    for (Uint i=0; i<k; i++)
    {
        n = (int)key[i];
        u += 7*n%31;
    }
    return u%139;
}

еще одна вещь, которую вы можете сделать, это умножить каждый символ int parse на индекс по мере его увеличения, как слово "медведь" (0 * b) + (1*e) + (2*a) + (3*r), что даст вам значение int для игры. первая хэш-функция выше сталкивается с "Здесь" и "слышит", но по-прежнему отлично дает некоторые хорошие уникальные значения. тот, что ниже, не сталкивается с "Здесь" и "слышит", потому что я умножаю каждый символ с индексом по мере его увеличения.

int keyHash(string key)
{
    unsigned int k = (int)key.length();
    unsigned int u = 0,n = 0;

    for (Uint i=0; i<k; i++)
    {
        n = (int)key[i];
        u += i*n%31;
    }
    return u%139;
}

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

int generatehashkey(const char *name)
{
        int x = tolower(name[0])- 97;
        if (x < 0 || x > 25)
           x = 26;
        return x;
}

что это в основном делает слова хэшируются по первой букве. Итак, слово, начинающееся с "a", получит хэш-ключ 0, " b "получит 1 и так далее, а" z " будет 25. Числа и символы будут иметь хэш-ключ 26. Это дает преимущество; вы можете посчитать легко и быстро, где данное слово будет индексироваться в хэш-таблице, так как все в алфавитном порядке, что-то вроде этого: Код можно найти здесь:https://github.com/abhijitcpatil/general

предоставление следующего текста в качестве ввода:

это будет выход:

0 --> a a about asked and a Atticus a a all after at Atticus
1 --> but but blue birds. but backyard
2 --> cribs corn can cans
3 --> do don’t don’t don’t do don’t do day
4 --> eat enjoy. except ever
5 --> for for father’s
6 --> gardens go
7 --> hearts heard hit
8 --> it’s in it. I it I it’s if I in
9 --> jays Jem
10 --> kill kill know
11 --> 
12 --> mockingbird. music make Maudie Miss mockingbird.”
13 --> nest
14 --> out one one only one
15 --> people’s
16 --> 17 --> right remember rather
18 --> sin sing said. she something sin say sin Shoot shot said
19 --> to That’s their thing they They to thing to time the That to the the tin to
20 --> us. up us
21 --> 
22 --> why was was want
23 --> 
24 --> you you you’ll you
25 --> 
26 --> “Mockingbirds ” “Your ‘em “I’d