2013-03-18 16 views
10

Potrzebuję utworzyć funkcję wyszukiwania, w której para (X, Y) odpowiada określonej wartości Z. Jednym z głównych wymagań jest to, że muszę to zrobić tak blisko złożoności O (1), jak tylko potrafię. Moim planem jest użycie nieuporządkowanej_mapy.C++ - złożoność nieuporządkowanej mapy

Generalnie nie używam tabeli hash do wyszukiwania, ponieważ czas wyszukiwania nigdy nie był dla mnie ważny. Czy mam rację, myśląc, że dopóki zbuduję unordered_map bez kolizji, mój czas wyszukiwania będzie O (1)?

Moją obawą jest wtedy, jaka staje się złożoność, jeśli klucz nie jest obecny na nieuporządkowanej mapie. Jeśli używam na przykład unordered_map :: find():, aby ustalić, czy klucz znajduje się w mojej tablicy mieszającej, w jaki sposób otrzymam odpowiedź? Czy to rzeczywiście jest iteracja nad wszystkimi kluczami?

Bardzo doceniam pomoc.

Odpowiedz

4

Standardowe bardziej lub mniej wymaga stosowania segmentów do rozmiar zderzenia , co oznacza, że ​​rzeczywista patrzeć razem prawdopodobnie liniowo zależny od liczby elementów w wiadra, niezależnie od tego, czy element ma lub nie. Możliwe jest wykonanie O (lg N), ale zwykle nie jest to robione, , ponieważ liczba elementów w wiadrze powinna być niewielka, , jeśli tabela mieszania jest używana poprawnie.

Aby upewnić się, że liczba elementów w łyżce jest mała, użytkownik musi uzyskać pewność, że funkcja mieszania jest skuteczna. To, co jest skuteczne, zależy od typów i wartości mieszanych. (W implementacji MS używany jest FNV, który jest jednym z najlepszych popularnych skrótów , ale jeśli masz specjalną wiedzę o rzeczywistych danych, które zobaczysz, być może będziesz w stanie to zrobić lepiej.) Inna rzecz, która może Pomóż zmniejszyć liczbę elementów na wiadro o rozmiarach , aby wymusić więcej łyżek lub użyć mniejszego współczynnika obciążenia. Po pierwsze, można przekazać minimalną początkową liczbę wiaderek jako argument do konstruktora. Jeśli znasz całkowitą liczbę elementów, które będą na mapie, możesz kontrolować współczynnik obciążenia w ten sposób. Po napełnieniu stołu możesz także podać minimalną liczbę kubełków , dzwoniąc pod numer rehash. W przeciwnym razie dostępna jest funkcja, której możesz użyć. To nie może nic zrobić, ale w każdej rozsądnej implementacji będzie. Zauważ, że jeśli użyjesz go na już wypełnionym wypełnionym unordered_map, prawdopodobnie będziesz musiał później zadzwonić pod numer unordered_map<>::rehash.

(Istnieje kilka rzeczy, których nie rozumiem o standardowej unordered_map: dlaczego współczynnik obciążenia jest float, zamiast double, dlaczego to nie jest wymagane, aby mieć wpływ, a dlaczego nie automatycznie zadzwoń rehash dla ciebie)

1

Jak w przypadku każdej tabeli mieszania, najgorszy przypadek jest zawsze złożoność liniowa (Edit: jeśli zbudowany mapę bez żadnych kolizji jakbyś stwierdził w swoim pierwotnym stanowisku, to nigdy nie zobaczysz tej sprawy):

http://www.cplusplus.com/reference/unordered_map/unordered_map/find/

Złożoność przeciętnego przypadku: stała. Najgorszy przypadek: liniowy w rozmiarze kontenera.

Return Value iterator do elementu, jeśli podana wartość klucz zostanie znaleziony, lub unordered_map :: end czy podany klucz nie znajduje się w pojemniku.

Jednak ponieważ unordered_map może zawierać tylko unikalne klucze, widać średnią złożoność stałym czasie (kontener pierwsze kontrole indeksu hash, a następnie wykonuje iteracje nad wartościami w tym indeksie).

Myślę, że dokumentacja unordered_map::count funkcji jest bardziej pouczający:

Przeszukuje pojemnik na elementy, których kluczem jest k i zwraca liczbę elementów znalezionych. Ponieważ kontenery unordered_map nie pozwalają na zduplikowanie kluczy, oznacza to, że funkcja faktycznie zwraca 1, jeśli element z tym kluczem istnieje w kontenerze, a w przeciwnym wypadku: zero.

+0

jestem teraz mylić odpowiedź JAKAR tutaj. http://stackoverflow.com/questions/4395050/finding-value-in-unordered-map chciałbym zinterpretować ten komentarz to znaczy można osiągnąć. Czy tak nie jest? – user1764386

+0

@ user1764386: Cóż, find musi zwrócić * coś *, jeśli nie może zwrócić iteratora do twojej wartości, więc unordered_map :: end był najlepszym wyborem. – AndyG

+0

dziękuję za pomoc. Chodziło mi o to, że jestem nieco zdezorientowany jego odpowiedzią, ponieważ interpretowałem to w ten sposób, że złożoność będzie lepsza niż O (N), jeśli klucz nie znajduje się w nieuporządkowanej_mapie. – user1764386

2

Brak kolizji w haszowanej strukturze danych jest niesamowicie trudny (jeśli nie jest niemożliwy dla danej funkcji hash i wszelkiego rodzaju danych). Wymagałoby to również rozmiaru stołu dokładnie równego liczbie kluczy. Nie, to nie musi być takie surowe. Dopóki funkcja skrótu rozkłada wartości w stosunkowo jednolity sposób, będziesz mieć złożoność wyszukiwania w postaci O(1).

Tabele skrótów są zwykle tylko tablicami z połączonymi listami zajmującymi się kolizjami (jest to metoda łączenia - istnieją inne metody, ale jest to prawdopodobnie najbardziej wykorzystywany sposób radzenia sobie z kolizjami). Zatem, aby znaleźć, jeśli wartość jest zawarta w wiadrze, będzie musiała (potencjalnie) iterować nad wszystkimi wartościami w tym wiadrze. Jeśli więc funkcja mieszająca zapewnia jednolitą dystrybucję, a są wiadra N, a łącznie wartości M, powinny być (średnio) M/N wartości na wiadro.Dopóki ta wartość nie jest zbyt duża, umożliwia to wyszukiwanie O(1).

Tak, jak trochę długo zdyszany odpowiedzi na pytanie, jak długo funkcja skrótu jest rozsądna, dostaniesz O(1) odnośnika, z jego konieczności iteracyjnego (średnio) O(M/N) klawiszy, aby dać " negatywny "wynik.