it-swarm.com.de

Was ist die beste 32-Bit-Hash-Funktion für kurze Zeichenfolgen (Tag-Namen)?

Was ist die beste 32-Bit-Hash-Funktion für relativ kurze Zeichenfolgen?

Zeichenfolgen sind Markennamen, die aus englischen Buchstaben, Zahlen, Leerzeichen und einigen zusätzlichen Zeichen bestehen (#, $, ., ...). Zum Beispiel: Unit testing, C# 2.0.

Ich bin auf der Suche nach "best", da bei "minimalen Kollisionen" die Leistung für meine Ziele nicht wichtig ist.

43
Andrey Shchekin

Wenn die Leistung nicht wichtig ist, nehmen Sie einfach einen sicheren Hash wie MD5 oder SHA1 und schneiden Sie die Ausgabe auf 32 Bit ab. Dadurch erhalten Sie eine Verteilung von Hash-Codes, die sich nicht von zufällig unterscheiden lässt.

22
Nick Johnson

Ich bin nicht sicher, ob es die beste Wahl ist, aber hier ist eine Hash-Funktion für Strings:

Die Praxis des Programmierens (HASH TABLES, S. 57)

/* hash: compute hash value of string */
unsigned int hash(char *str)
{
   unsigned int h;
   unsigned char *p;

   h = 0;
   for (p = (unsigned char*)str; *p != '\0'; p++)
      h = MULTIPLIER * h + *p;
   return h; // or, h % ARRAY_SIZE;
}

Empirisch, die Werte 31 und 37 haben erwies sich als gute Wahl für die
Multiplikator in einer Hash-Funktion für ASCII - Zeichenfolgen.

22

Es tut mir leid für die sehr späte Antwort. Anfang dieses Jahres habe ich eine Seite mit dem Titel Hashing Short Strings verfasst, die in dieser Diskussion hilfreich sein könnte. Zusammenfassend habe ich festgestellt, dass CRC-32 und FNV-1a für das Hashing kurzer Strings überlegen sind. Sie sind effizient und werden in meinen Tests weit verbreitet und kollisionsfrei erzeugt. Ich war überrascht zu erfahren, dass MD5, SHA-1 und SHA-3 eine kleine Anzahl von Kollisionen verursachten, wenn die Ausgabe gefaltet auf 32 Bit war.

14
gfkeogh

Sie könnten murmurhash2 ausprobieren. Es ist schnell, auch für kleine Saiten, und hat einen guten Mischendschritt, so dass es auch für sehr kleine Saiten geeignet ist.

1

Wenn Ihr Programm mit anderen Systemen kommunizieren muss, verwenden Sie besser einen bekannten Algorithmus. Der schnelle und schmutzige Weg ist mit ersten mehreren Zeichen von md5-Hash . Sie brauchen keine Stunden oder Tage, um die Räder in Ihrem Projekt zu erfinden. 

Der Nachteil besteht darin, eine viel höhere Chance auf Kollisionen zu bekommen. Wenn Ihr Hash jedoch für eine Sitzung mit Zeitstempel oder eine kurze Lebenszyklusaufgabe bestimmt ist. Es ist kein Problem, dies zu verwenden.

0
Yi Jiang

Wenn Benutzer selten neue Tags hinzufügen, können Sie einen perfekten Hash ( http://en.wikipedia.org/wiki/Perfect_hash_function ) verwenden, der jedes Mal neu berechnet wird, wenn ein neuer Tag hinzugefügt wird. Ohne zu wissen, welches Problem Sie wirklich lösen wollen, müssen Sie herausfinden, was Sie tun könnten.

0
user97370

Verwenden Sie die MaPrime2c-Hashfunktion:

 static const unsigned char sTable [256] = 
 {
 0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf, 0xf9, 
 0xe7,0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52,0x95,0xd9,0x1e, 0x4e, 0x38,0x44,0x28, 
 0x0a, 0xdf, 0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a, 0xc3,0xe9,0xfa, 0x3d, 0x53,. 0x96,0x84,0x6b, 0xba, 0xf2,0x63,0x9a, 0x19,0x7c, 0xae, 0xe5,0xf5,0xf7,0x16,0x6a, 0xa2, 
 0x39,0xb6,0x7b, 0x0f, 0xc1,0x93,0x81,0x1b, 0xee, 0xb4,0x1a, 0xea, 0xd0,0x91,0x2f, 0xb8, 
 0x55,0xb9,0xda, 0x85,0x3f, 0x41,0xbf, 0xe0,0x5a, 0x58,0x80,0x5f, 0x66,0x0b, 0xd8,0x90,. 0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d, 0x98,0x9b, 0x76, 
 0x97,0xfc, 0xb2,0xc2,0xb0,0xfe, 0xdb, 0x20,0xe1,0xeb, 0xd6,0xe4,0xdd, 0x47,0x4a, 0x1d, 
 0x42,0xed, 0x9e, 0x6e, 0x49,0x3c, 0xcd, 0x43,0x27,0xd2,0x07,0xd4,0xde, 0xc7,0x67,0x18, 
 0x89,0xcb, 0x30,0x1f, 0x8d, 0xc6,0x8f, 0xaa, 0xc8,0x74,0xdc, 0xc9,0x5d, 0x5c, 0x31,0xa4, 
 0x70,0x88,0x61,0x2c, 0x9f, 0x0d, 0x2b, 0x87,0x50,0x82,0x54,0x64,0x26,0x7d, 0x03,0x40, 
 0x34,0x4b, 0x1c, 0x73,0xd1,0xc4,0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6,0x3e, 0x5b, 0xa5, 
 0xad, 0x04,0x23,0x9c, 0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e, 0xff, 0x8c, 0x0e, 0xe2, 
 0x0c, 0xef, 0xbc, 0x72,0x75,0x6f, 0x37,0xa1,0xec, 0xd3,0x8e, 0x62,0x8b, 0x86,0x10,0xe8,. 0x08,0x77,0x11,0xbe, 0x92,0x4f, 0x24,0xc5,0x32,0x36,0x9d, 0xcf, 0xf3,0xa6,0xbb, 0xac, 
 0x5e, 0x6c, 0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd, 0xa8,0x3a, 0x01,0x05,0x59,0x2a, 0x46 
 }; 


 #define PRIME_MULT 1717 


 unsigned int 
 maPrime2cHash (unsigniertes Zeichen * str, vorzeichenlose int-len) 
 {
 unsigned int hash = len, i; 


 für (i = 0; i! = len; i ++, str ++) 
 {

 hash ^ = sTable [(* str + i) & 255]; 
 Hash = Hash * PRIME_MULT; 
 } 

 Rückgabe-Hash; 
 } 

und siehe www.amsoftware.narod.ru/algo2.html für MaFastPrime, MaRushPrime usw.

0
Alexander

Das hängt von Ihrer Hardware ab. Bei moderner Hardware, z. B. Intel/AMD mit SSE4.2 oder arm7, sollten Sie die internen _mm_crc32_uxx-Eigenheiten verwenden, da diese für kurze Zeichenfolgen optimal sind. (Für lange Schlüssel auch, dann aber lieber Adler's Version verwenden, wie in zlib)

Auf alter oder unbekannter Hardware entweder Laufzeitprüfung für die SSE4.2- oder CRC32-Funktion oder nur eine der einfachen guten Hash-Funktionen. Z.B. Murmur2 oder Stadt

Eine Übersicht über Qualität und Leistung finden Sie hier: https://github.com/rurban/smhasher#smhasher

Es gibt auch alle Implementierungen. Bevorzugt werden https://github.com/rurban/smhasher/blob/master/crc32_hw.c und https://github.com/rurban/smhasher/blob/master/MurmurHash2.cpp

Wenn Sie die Schlüssel im Voraus kennen, verwenden Sie einen perfect-Hash, keine Hash-Funktion. Z.B. gperf oder mein phash: https://github.com/rurban/Perfect-Hash#name

Heutzutage ist eine perfekte Hash-Erzeugung über einen c-Compiler so schnell, dass Sie sie sogar spontan erstellen und laden können.

0
rurban