Хорошая хэш-функция для строк
Я пытаюсь придумать хорошую хэш-функцию для строк. И я подумал, что было бы неплохо суммировать значения 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-адреса, эта хэш-функция проявил ужасное поведение.
гуава это
HashFunction
(документация) обеспечивает приличные номера-крипто-сильная хеширования.
эта функция, предоставленная ником, хороша, но если вы используете новую строку(byte[] bytes) для преобразования в строку, это не удалось. Вы можете использовать эту функцию для этого.
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; }
Если вы хотите увидеть реализации отраслевых стандартов, я бы посмотрел на 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; }
здесь ссылка это объясняет много различных хэш-функций, на данный момент я предпочитаю эльф хэш-функции для вашей конкретной проблемы. Она принимает в качестве входных данных строку произвольной длины.
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