2009-04-09 11 views
10

Domeną zainteresowania jest dopasowywanie ciągów znaków. Załóżmy, że mam taką strukturę.Jak zaprojektowałbyś funkcję idealnego skrótu?

typedef struct 
{ 
    char *name, 
    int (*function)(); 

} StringArray 

StringArray s[] = 
{ 
    {"George", func1}, 
    {"Paul", func2}, 
    {"Ringo", func3}, 
    {"John", func4}, 
    {"",  NULL} /* End of list */ 
} 

W tablicy znajduje się stała liczba ciągów. Są one zakodowane jak na przykładzie. Jeśli tabela ulegnie zmianie, konieczna będzie ponowna ocena jakości funkcji skrótu.

Chcę zastosować funkcję skrótu do napisu, a jeśli ciąg pasuje do jednej w tablicy, , a następnie wywołaj funkcję. Do tego potrzebna jest idealna funkcja skrótu. Żadne kolizje nie są dozwolone. Celem wymagającego skrótu jest uzyskanie O (1) wydajności podczas wyszukiwania.

Jakie masz pomysły dotyczące projektowania funkcji?

+0

Nie sądzę spam oznacza co myślisz to znaczy –

+0

@Mitch: Czy to znaczy, że jest to pytanie, które może być łatwo googled? –

+0

@ j_random_hacker: Zrobiłem. Ale jest późno i to nie jest spam ... –

Odpowiedz

16

Zobacz stronę gperf domu.

+0

Część grzebiącą jest to, że istnieje łącze do tego na dole strony wikipedii. – EvilTeach

0

Można używać map

std::string foo() { return "Foo"; } 
std::string bar() { return "Bar"; } 

int main() 
{ 
    std::map<std::string, std::string (*)()> m; 
    m["foo"] = &foo; 
    m["bar"] = &bar; 
} 
+0

std :: mapa nie korzysta z hasha - jest to oparte na drzewie –

+0

dlaczego wymyślić koło, możesz użyć istniejących bibliotek, takich jak mapa. – Vinay

+1

Być może pytający chciał mieć charakterystykę wydajnościową haszu, a nie poszukiwań drzew? –

1
+0

Nie odpowiada bezpośrednio na pytanie, ale dobre linki. – EvilTeach

+0

Czy osoba przekazująca (do tego bardzo starego pytania) proszę zostawić komentarz. Dzięki. –

0

Jeśli kolizje są absolutnie niedozwolone, jedyną opcją jest, aby śledzić każdy ciąg w bazie danych, co nie jest chyba najlepszym sposobem udać się.

Co mogę zrobić, to zastosować jeden z istniejących wspólnych silnych algorytmów mieszających, takich jak: MD5 lub SHA. Wokół są miriadki próbek, na przykład jeden: http://www.codeproject.com/KB/security/cryptest.aspx

-1

Cóż, nie ma idealnej funkcji skrótu.

Masz kilka, które minimalizują kolizje, ale żadne ich nie eliminuje.

nie może doradzić jedno ale: P

EDIT: Rozwiązanie nie może być znalezienie idealnego funkcji skrótu. Rozwiązaniem jest świadomość kolizji. Zwykle funkcja mieszająca ma kolizje. To oczywiście zależy od zbioru danych i rozmiaru wynikowego kodu skrótu.

+0

http://en.wikipedia.org/wiki/Perfect_hashing –

+0

@Adam: Jest dość duże zastrzeżenie, ponieważ dotyczy to tylko różnych zestawów danych. Ponieważ PO nie wspomniał o ograniczeniu używanych łańcuchów, zgadzam się z Megacanem, że w tym przypadku nie ma idealnego skrótu. +1. – sipwiz

+0

Pytający czyni tę wzmiankę, przynajmniej w domyśle - byli tylko czterej Beatlesi) lub siz, jeśli włączysz perkusistę zwolnionego i Stu whatsisname) - wciąż stały zestaw danych. –

0

Użyj zbalansowanego drzewa binarnego. To zachowanie WIEM jest ZAWSZE O (logn).

Bardzo nie lubię haszysz. Ludzie nie zdają sobie sprawy z tego, ile ryzyka podejmują z ich algorytmem. Przeprowadzają niektóre dane testowe, a następnie wdrażają je w terenie. NIGDY nie widziałem wdrożonego algorytmu mieszania, który jest sprawdzany pod kątem zachowania w terenie.

O (log n) jest prawie zawsze akceptowalny zamiast O (1).

+0

"O (log n) jest prawie zawsze akceptowalne zamiast O (1)." W wielu aplikacjach to stwierdzenie jest błędne. Wystarczy zwiększyć liczbę punktów danych powyżej kilku milionów, aby to zobaczyć. –

+0

Po wykonaniu tej czynności przetestuj. Hashe nie dają gwarantowanych wyników, chyba że wiesz z góry, jakie mogą być wszystkie możliwe dane wejściowe. Funkcja skrótu, która ma tendencję do zbijania danych wejściowych, prawdopodobnie nie da ci O (1). –

+0

W tym przypadku wszystkie wejścia są znane. Siedzą w szyku. i ciąg wejściowy jest dopasowaniem ścisłym lub nie pasującym. – EvilTeach

2

Podsumowanie zawiera zarówno C, jak i C++. Którego szukasz? C i C++ są dwoma odrębnymi językami i różnią się znacznie pod względem obsługi łańcuchów i struktur danych (a fakt, że te C działają w C++, nie zmienia tego).

Dlaczego, konkretnie, chcesz uzyskać idealną funkcję skrótu? Czy chcesz powiązać ciąg z funkcją i pomyśleć, że byłby to dobry sposób na zrobienie tego? Czy to jest zadanie domowe? Czy masz powód, aby nie używać mapy <> w C++? (Lub unordered_map <> jeśli jest dostępny?)

Jeśli potrzebujesz idealnego skrótu, jakie są ograniczenia na strunach? Czy będzie jakiś ustalony zestaw, który chcesz wysłać? A co z ciągami, które nie pasują do jednego z zestawów? Czy chcesz zaakceptować trafienia z losowych ciągów lub czy liczba przychodzących łańcuchów jest ograniczona?

Jeśli możesz edytować swoje pytanie, aby dołączyć takie informacje, możemy być bardziej przydatni.

EDIT (w odpowiedzi na dwa pierwsze komentarze):

OK, powinniśmy spojrzeć na rozwiązania C, ponieważ przypuszczalnie chcesz to zarówno dla dysku C i C++ pracy. Prawdopodobnie chcesz występu, ale czy przetestowałeś? Jeśli mamy do czynienia z ciągami wchodzącymi do systemu I/O, czas prawdopodobnie skróci czas wysyłki.

Spodziewasz się arbitralnych ciągów znaków. Oczekiwanie na doskonałą funkcję skrótu, która pozwoli uniknąć kolizji z losowych danych, jest nieco spora, więc musisz to rozważyć.

Czy brałeś pod uwagę trie? Może być bardziej wydajna niż idealna funkcja skrótu (lub nie musi być), powinna być dość łatwa do implementacji w C, i pozwoli uniknąć problemów z ponawieniem listy wysyłanych łańcuchów lub możliwych kolizji.

+0

Koduję zarówno w językach c, jak i C++, a Bóg mi pomaga Pro * C. O (1) mieszanie dla wydajności. Lol, bez zadań domowych. Szukam narzędzia do przyspieszenia kodu krytycznego pod względem wydajności. Przykład jest prosty do celów dyskusji. Używanie rzeczywistego świata nie jest. – EvilTeach

+0

Struny będą bardzo długie. Żadne z nich nie będzie miało długości zero. Praktycznie, żaden ciąg w tablicy nie będzie dłuższy niż 32 znaki. To, co odwiedzający wywołuje, może mieć dowolną długość, ale jeśli jest dłuższy niż ciągi w tabeli, to jest to przypadek braku dopasowania – EvilTeach

+0

+1 dla wzmianki o trie. –

0

Końcowym rezultatem tego ćwiczenia było

  • Steal szereg zorientowanych ciągów funkcji mieszających się siatki.
  • Zbuduj rodzaj klasy fabrycznej, która przetestowała każdą z funkcji w zestawie danych z zakresem wartości operatorów mod, szukając najmniejszego idealnego skrótu, który działa z tą funkcją.
  • Ten konstruktor domyślny klasy fabrycznej zwraca ciąg znaków, który reprezentuje zbiór argumentów, które po użyciu wybiera poprawną funkcję haszowania, oraz rozmiar modu, aby uzyskać idealny skrót, który wymaga najmniejszej ilości pamięci.
  • pod normalnym użyciem, po prostu tworzysz instancję klasy za pomocą zwróconych argumentów, a klasa umieszcza się w stanie roboczym z pożądanymi funkcjami.
  • Ten konstruktor sprawdza, czy nie ma kolizji i przerwie, jeśli są.
  • W przypadku, gdy nie znaleziono idealnego skrótu, ulega on degradacji do wyszukiwania binarnego w posortowanej wersji tabeli wejściowej.

Dla zestawu tablic, które mam w mojej domenie, wydaje się, że działa bardzo dobrze. Ewentualną przyszłą optymalizacją byłoby wykonanie tego samego rodzaju testów na podciągach danych wejściowych. W przykładowym przypadku pierwsza litera każdego imienia muzyczki wystarczy, aby je odróżnić. Wówczas trzeba będzie zrównoważyć koszt rzeczywistej funkcji hashującej z użytą pamięcią.

Dziękuję wszystkim, którzy wnieśli swoje pomysły.

Zło

Powiązane problemy