Chcę wydajnie filtrować listę liczb całkowitych dla duplikatów w taki sposób, że tylko wynikowy zestaw musi być przechowywany.
Można to zobaczyć na jeden sposób:
- mamy szereg liczb całkowitych z duży (powiedzmy )
- mamy funkcję z podobno wieloma kolizjami (obrazy są równomiernie rozmieszczone w )
- następnie musimy przechowywać , to jest
Mam dość dokładne (probabilistyczne) oszacowanie tego, co jest i dlatego może wcześniej przydzielić struktury danych (powiedzmy ).
Miałem kilka pomysłów, ale nie jestem pewien, jakie byłoby najlepsze podejście:
- zestaw bitów nie wchodzi w rachubę, ponieważ zestaw danych wejściowych nie mieści się w pamięci.
- tablica skrótów, ale (1) wymaga trochę pamięci, powiedzmy 150% z oraz (2) tabela musi zostać zbadana po zbudowaniu, co wymaga dodatkowego czasu z powodu narzutu pamięci.
- „w locie”, najlepiej z złożoność (sortowanie nieporównywalne). W związku z tym nie jestem pewien, jaka jest główna różnica między sortowaniem kubełkowym a sortowaniem flash .
- prosta tablica z binarnym drzewem wyszukiwania, ale to wymaga czas.
- być może użycie filtrów Blooma lub podobnej struktury danych może być przydatne w rozluźnieniu (z fałszywymi pozytywami) problemu.
Wydaje się, że niektóre pytania dotyczące stackoverflow dotyczą tego rodzaju rzeczy ( /programming/12240997/sorting-array-in-on-run-time , /programming/3951547/java -array-find-duplicates ), ale żaden nie wydaje się odpowiadać moim wymaganiom.
Odpowiedzi:
Dlaczego nie bin i łańcuch?
Pomysł polega na przechowywaniu dodatnich liczb całkowitych reprezentowanych przezn=k+m bity w tablicy A z 2k wpisy reprezentujące zakresy wartości: wpis A[y] , y≥0 , reprezentuje zakres [2my,2m(y+1)−1] . Dla każdego1≤x<2n możemy pisać x=2my+z gdzie y ma k bity i z ma m bitów Spróbuj przechowywaćz (nie x !) na miejscu y :
KiedyA[y]=z już nic nie rób: x jest duplikatem.
KiedyA[y] jest niezainicjowany, zapisz z w A[y] .
W przeciwnym razie przechowuj indeks w osobnej tablicy używanej do łączenia łańcuchaz (które zderzyły się w y ) na połączonych listach. Będziesz musiał przeszukiwać liniowo listę kierowaną przezA[y] i, w zależności od tego, co odkryje wyszukiwanie, potencjalnie wstaw z na listę.
Na końcu,f(S) można łatwo odzyskać, zapętlając zainicjowane wpisy A oraz - łącząc tylko dwa ciągi bitów - ponownie je łącząc z znalezione w miejscu y (bezpośrednio lub w obrębie łańcucha tam wymienionego) do oryginalnej wartości x=2my+z .
Gdy rozkład jest zbliżony do jednorodnego i2k przekracza N , łańcuchów nie będzie dużo (można to ocenić w zwykły sposób), a łańcuchy będą zwykle krótkie. Gdy rozkład jest nierównomierny, algorytm nadal działa, ale może osiągnąć kwadratowe taktowanie. Jeśli to możliwe, użyj czegoś wydajniejszego niż łańcuchy (i zapłać trochę kosztów ogólnych za przechowywanie).
Potrzebne miejsce jest co najwyżej2n bity dla A i 22k bity dla łańcuchów (przy założeniu m≤k ). To jest dokładnie miejsce potrzebne do przechowywania2k wartości n bitów każdy. Jeśli masz pewność co do jednolitości, możesz zbytnio przydzielić miejsce na łańcuchy. Jeśli niejednolity charakter jest możliwy, możesz chcieć zwiększyćk i w pełni popieramy przechowywanie łańcucha.
Alternatywnym sposobem myślenia o tym rozwiązaniu jest to, że jest to tablica skrótów ze szczególnie przyjemną funkcją skrótu (weźk najbardziej znaczące bity) i dlatego musimy przechowywać tylko najmniej znaczące m=n−k bity w tabeli.
Istnieją sposoby nałożenia pamięci dla łańcuchów z pamięcią dlaA ale nie wydaje się to warte zawracania głowy, ponieważ nie zaoszczędziłoby wiele (zakładając m jest znacznie mniejszy niż k ) i utrudniają tworzenie, debugowanie i konserwację kodu.
źródło