Masz dobrą funkcję hash dla tabeli hashowej C++?

Potrzebuję implementacji funkcji skrótu zorientowanej na wydajność w C++ do tabeli skrótu, którą będę kodował. Rozejrzałem się już i znalazłem tylko pytania pytające, jaka jest dobra funkcja hash "w ogóle". Rozważałem CRC32 (ale gdzie znaleźć dobrą implementację?) oraz kilka algorytmów kryptograficznych. Mój stół ma jednak bardzo specyficzne wymagania.

Oto jak będzie wyglądał stół:

100,000 items max
200,000 capacity (so the load is 0.5)
hashing a 6-character string which is a part of English sentence
     examples: "become"    "and he"    ", not "

pierwszy priorytet mojej tabeli hash jest szybki wyszukiwanie (odzyskiwanie). Szybkie wstawianie nie jest ważne, ale przyjdzie wraz z szybkim wyszukiwaniem. Usuwanie nie jest ważne, a ponowne hasowanie nie jest czymś, nad czym będę się zastanawiał. Aby poradzić sobie z kolizjami, prawdopodobnie użyję oddzielnego łańcucha zgodnie z opisem tutaj . Przejrzałem już ten artykuł , ale chciałbym zasięgnąć opinii tych, którzy wcześniej zajmowali się takim zadaniem.

Author: Bill the Lizard, 2009-03-10

9 answers

Teraz chcesz hasha, i chcesz cośbłyskawicznego , co by w Twoim przypadku zadziałało, ponieważ twoje struny mają tylko 6 znaków, możesz użyć tej magii:

size_t precision = 2; //change the precision with this
size_t hash(const char* str)
{
   return (*(size_t*)str)>> precision;
}

CRC jest dla slowpokes ;)

Explanation: Działa to poprzez ustawienie zawartości wskaźnika łańcuchowego, aby "wyglądał jak" size_t (int32 lub int64 w oparciu o optymalne dopasowanie dla Twojego sprzętu). Tak więc zawartość łańcucha jest interpretowana jako liczba nieprzetworzona, nie martw się już o znaki, i wtedy bit-przesuń to wymaganą precyzję (poprawiasz tę liczbę do najlepszej wydajności, znalazłem 2 działa dobrze do haszowania ciągów w zestawie kilku tysięcy).

Również naprawdę fajną częścią jest każdy porządny kompilator na nowoczesnym sprzęcie będzie haszował taki ciąg w 1 instrukcji montażu, trudno to przebić;)

 24
Author: Robert Gould,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 04:23:42

Ten prosty wielomian działa zaskakująco dobrze. Dostałem go od Paula Larsona z Microsoft Research, który studiował szeroką gamę funkcji skrótu i mnożników skrótu.

unsigned hash(const char* s, unsigned salt)
{
    unsigned h = salt;
    while (*s)
        h = h * 101 + (unsigned) *s++;
    return h;
}

salt powinna być zainicjalizowana do wybranej wartości losowo przed utworzeniem hashtable w celu obrony przed atakamitabela hash . Jeśli nie jest to dla Ciebie problemem, po prostu użyj 0.

Rozmiar tabeli jest również ważny, aby zminimalizować kolizje. Wygląda na to, że twoja jest w porządku.

 13
Author: George V. Reilly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-02 20:53:49

Boost.Functional / Hash może Ci się przydać. Nie próbowałem, więc nie mogę ręczyć za jego wydajność.

Boost posiada również bibliotekę CRC .

Spojrzałbym na .Unordered first (tj. boost:: unordered_map). Używa map hash zamiast drzew binarnych dla kontenerów.

Wydaje mi się, że niektóre implementacje STL mają kontener hash_map w przestrzeni nazw stdext.

 6
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:36:14

Rozmiar Twojej tabeli będzie określał, jakiego rozmiaru hasha powinieneś użyć. Oczywiście chcesz zminimalizować kolizje. Nie jestem pewien, co określasz przez elementy max i pojemność (wydają mi się to samo) w każdym przypadku, które z tych liczb sugerują, że 32 bitowy hash byłby wystarczający. Możesz uciec z CRC16 (~65,000 możliwości), ale prawdopodobnie będziesz miał wiele kolizji do czynienia. Z drugiej strony kolizja może być szybsza niż CRC32 hash.

Powiedziałbym, idź z CRC32. Nie zabraknie dokumentacji i przykładowego kodu. Ponieważ masz swoje maksimum zorientowane i szybkość jest priorytetem, przejdź z tablicy wskaźników. Użyj skrótu do wygenerowania indeksu. Przy kolizji, inkrementuj indeks, aż trafisz w puste wiadro.. szybko i prosto.

 4
Author: Arnold Spence,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:17:31

Ponieważ przechowujesz angielskie słowa, większość twoich znaków będzie literami i nie będzie wiele różnic w najważniejszych dwóch bitach Twoich danych. Poza tym chciałbym zachować to bardzo proste, po prostu za pomocą XOR. W końcu nie szukasz siły kryptograficznej, ale tylko rozsądnie równomiernej dystrybucji. Coś w tym stylu:

size_t hash(const std::string &data) {
  size_t h(0);
  for (int i=0; i<data.length(); i++)
    h = (h << 6) ^ (h >> 26) ^ data[i];
  }
  return h;
}

Poza tym, czy patrzyłeś na STD::tr1::hash jako funkcję haszującą i / lub STD:: tr1:: unordered_map jako implementację hasz table? Korzystanie z nich byłoby prawdopodobnie zaoszczędzić wiele pracy w przeciwieństwie do wdrażania własnych klas.

 4
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:53:25

Priorytetem mojej tabeli hash jest szybkie wyszukiwanie (pobieranie).

Dobrze więc używasz odpowiedniej struktury danych, ponieważ wyszukiwanie w tabeli hash jest O (1)! :)

CRC32 powinien działać dobrze. Implementacja nie jest tak złożona, opiera się głównie na XORs. Upewnij się tylko, że używa dobrego wielomianu.
 2
Author: Bob Somers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:25:08

A może coś prostego:

// Initialize hash lookup so that it maps the characters
// in your string to integers between 0 and 31
int hashLookup[256];

// Hash function for six character strings.
int hash(const char *str)
{
    int ret = 0, mult = 1;
    for (const char *p = str; *p; *p++, mult *= 32) {
        assert(*p >= 0 && *p < 256);
        ret += mult * hashLookup[*p];
    }

    return ret;
}

Zakłada to 32-bitowe ints. Używa 5 bitów na znak, więc wartość hash ma tylko 30 bitów. Można to naprawić, być może, generując sześć bitów dla pierwszego jednego lub dwóch znaków. Jeśli zestaw znaków jest wystarczająco mały, możesz potrzebować nie więcej niż 30 bitów.

 2
Author: David Norman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:27:24

Jeśli potrzebujesz przeszukać krótkie ciągi i wstawianie nie jest problemem, może przydałoby się drzewo B, lub drzewo 2-3, w Twoim przypadku nie zyskasz wiele przez haszowanie.

Sposób, w jaki to zrobisz, polega na umieszczeniu litery w każdym węźle, więc najpierw sprawdzasz węzeł "a", następnie sprawdzasz dzieci "a"dla "p", a dzieci dla "p", a następnie "l" i "e". W sytuacjach, gdy masz "apple" I "apply", musisz szukać ostatniego węzła, (ponieważ jedyna różnica jest w ostatnim " e" i "y")

Ale w większości przypadków będziesz w stanie uzyskać słowo po kilku krokach ("ksylofon" => "x"->"ylofon"), więc możesz zoptymalizować w ten sposób. Może to być szybsze niż hashowanie

 2
Author: Robert Gould,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-10 03:33:01

Od C++11, C++ dostarcza std::hash< string >( string ). Jest to prawdopodobnie wydajna funkcja haszująca, która zapewnia dobry rozkład kodów haszujących dla większości łańcuchów.

Ponadto, jeśli myślisz o zaimplementowaniu tabeli hash, powinieneś teraz rozważyć użycie C++ std::unordered_map zamiast tego.

 0
Author: Raedwald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-05 15:09:42