Muszę obliczyć medianę biegu:
Dane wejściowe: , , wektor .
Wyjście: wektor , gdzie jest medianą .
(Brak oszustw z przybliżeniami; Chciałbym mieć dokładne rozwiązania. Elementy są dużymi liczbami całkowitymi.)
Istnieje prosty algorytm, który utrzymuje drzewo wyszukiwania o rozmiarze ; całkowity czas działania wynosi . („Drzewo wyszukiwania” odnosi się do wydajnej struktury danych, która obsługuje wstawianie, usuwanie i zapytania o medianę w czasie logarytmicznym).
Wydaje mi się to jednak trochę głupie. Skutecznie nauczymy się wszystkich statystyk zamówień we wszystkich oknach wielkości , nie tylko median. Co więcej, w praktyce nie jest to zbyt atrakcyjne, szczególnie jeśli jest duże (duże drzewa wyszukiwania są zwykle wolne, narzut w zużyciu pamięci nie jest trywialny, wydajność pamięci podręcznej jest często niska itp.).
Czy możemy zrobić coś znacznie lepszego?
Czy są jakieś dolne granice (np. Czy trywialny algorytm jest asymptotycznie optymalny dla modelu porównawczego)?
Edycja: David Eppstein podał dolną granicę dla modelu porównawczego! Zastanawiam się, czy można zrobić coś nieco sprytniejszego niż prosty algorytm?
Na przykład, czy moglibyśmy zrobić coś wzdłuż tych linii: podzielić wektor wejściowy na części wielkości ; posortuj każdą część (śledząc oryginalne pozycje każdego elementu); a następnie użyć wektora posortowanego w części, aby znaleźć działające mediany wydajnie bez żadnych struktur danych pomocniczych? Oczywiście nadal byłoby to , ale w praktyce sortowanie tablic jest zwykle znacznie szybsze niż utrzymywanie drzew wyszukiwania.
Edycja 2: Saeed chciał zobaczyć kilka powodów, dla których myślę, że sortowanie jest szybsze niż operacje drzewa wyszukiwania. Oto bardzo szybkie testy porównawcze, dla , :
- ≈ 8s: sortowanie wektorów z elementami każdy
- ≈ 10s: sortowanie wektora z elementami
- ≈ lata 80 .: wstawiania i usuwania w tablicy mieszającej o rozmiarze
- ≈ 390s: wstawiania i usuwania w zrównoważonym drzewie wyszukiwania o rozmiarze
Tabela skrótów jest tylko dla porównania; nie ma bezpośredniego zastosowania w tej aplikacji.
Podsumowując, mamy prawie 50-krotną różnicę w wydajności sortowania vs. zrównoważone operacje drzewa wyszukiwania. I wszystko pogorszy się, jeśli zwiększymy .
(Szczegóły techniczne: Dane = losowe 32-bitowe liczby całkowite. Komputer = typowy nowoczesny laptop. Kod testowy został napisany w C ++, przy użyciu standardowych procedur bibliotecznych (std :: sort) i struktur danych (std :: multiset, std :: unsorted_multiset). Użyłem dwóch różnych kompilatorów C ++ (GCC i Clang) oraz dwóch różnych implementacji biblioteki standardowej (libstdc ++ i libc ++). Tradycyjnie, std :: multiset został zaimplementowany jako wysoce zoptymalizowane drzewo czerwono-czarne.)
źródło
Odpowiedzi:
Oto dolna granica sortowania. Biorąc pod uwagę zestaw wejściowy o długości do posortowania, utwórz dane wejściowe do swojego problemu z medianą, składającego się z kopii liczby mniejszej niż minimum , następnie samego , a następnie kopii liczby większej niż maksimum i ustawić . Te prowadzące mediany tego wejścia są takie same jak na posortowanych w .S n n−1 S S n−1 S k=2n−1 S
Zatem w porównawczym modelu obliczeniowym wymagany jest czas . Być może, jeśli dane wejściowe są liczbami całkowitymi i używasz algorytmów sortowania liczb całkowitych, możesz to zrobić lepiej.Ω(nlogn)
źródło
Edycja: ten algorytm jest teraz prezentowany tutaj: http://arxiv.org/abs/1406.1717
Tak, aby rozwiązać ten problem, wystarczy wykonać następujące operacje:
Z grubsza chodzi o to, że:
Dla każdego :ja
Połączone listy są tylko tablicami indeksów typu element, więc są lekkie (poza tym, że lokalizacja dostępu do pamięci jest niska).k
Oto przykładowa implementacja i testy porównawcze:
Oto wykres czasów działania (dla ):n ≈ 2 ⋅ 106
źródło
Biorąc pod uwagę granice Davida, jest mało prawdopodobne, abyś mógł zrobić lepszy najgorszy przypadek, ale istnieją lepsze algorytmy wrażliwe na wyniki. W szczególności, jeśli wyniku jest liczba median, możemy rozwiązać problem w czasie O ( n log m + m log n ) .m O ( n logm + m logn )
Aby to zrobić, zastąp zbalansowane drzewo binarne zrównoważonym drzewem binarnym składającym się tylko z tych elementów, które w przeszłości były medianami, plus dwa stosy Fibonacciego między każdą parą poprzednich median (po jednym dla każdego kierunku), a także zliczaj, abyśmy mogli zlokalizuj, która kupa Fibonacciego zawiera określony element w kolejności. Nie zawracaj sobie głowy usuwaniem elementów. Po wstawieniu nowego elementu możemy zaktualizować naszą strukturę danych w czasie . Jeśli nowe liczby wskazują, że mediana znajduje się w jednym z hałd Fibonacciego, potrzeba dodatkowego O ( log n ), aby wyciągnąć nową medianę. To O ( log n )O ( logm ) O ( logn ) O ( logn ) ładunek występuje tylko raz na medianę.
Gdyby istniał czysty sposób usuwania elementów bez uszkadzania ładnej złożoności Fibonacciego, przechodzilibyśmy do , ale nie jestem pewien, czy jest to możliwe.O ( n logm + m logk )
źródło