Uważam, że istnieje sposób na znalezienie k-tego największego elementu w nieposortowanej tablicy o długości n w O (n). A może to „oczekiwane” O (n) lub coś takiego. Jak możemy to zrobić?
performance
algorithm
big-o
MrDatabase
źródło
źródło
Odpowiedzi:
Nazywa się to znajdowaniem statystyki k-tego rzędu . Istnieje bardzo prosty algorytm randomizowany (zwany szybkim wyborem ), który zajmuje
O(n)
średni czas,O(n^2)
najgorszy przypadek, oraz dość skomplikowany algorytm nielosowy (zwany introseleksem ), który zajmujeO(n)
najgorszy czas. Jest trochę informacji na Wikipedii , ale to nie jest zbyt dobre.Wszystko, czego potrzebujesz, znajduje się w tych slajdach PowerPoint. Aby wyodrębnić podstawowy algorytm algorytmuO(n)
najgorszego przypadku (introselect):Jest to również bardzo ładnie wyszczególnione w książce Wprowadzenie do algorytmów autorstwa Cormen i in.
źródło
Jeśli chcesz prawdziwego
O(n)
algorytmu, w przeciwieństwie doO(kn)
czegoś podobnego, powinieneś użyć szybkiego wyboru (jest to po prostu szybki sort, w którym wyrzucasz partycję, która Cię nie interesuje). Mój prof ma świetny opis, z analizą środowiska wykonawczego: ( odniesienie )Algorytm QuickSelect szybko znajduje k-ty najmniejszy element nieposortowanej tablicy
n
elementów. Jest to algorytm Randomized , więc obliczamy najgorszy spodziewany czas działania.Oto algorytm.
Jaki jest czas działania tego algorytmu? Jeśli przeciwnik rzuci za nas monety, może się okazać, że oś jest zawsze największym elementem i
k
wynosi zawsze 1, co daje czas działaniaAle jeśli wybory są rzeczywiście losowe, oczekiwany czas działania jest podawany przez
gdzie przyjmujemy niezupełnie uzasadnione założenie, że rekurencja zawsze wyląduje w większym
A1
lubA2
.Zgadnijmy
T(n) <= an
dla niektórycha
. Potem dostaniemya teraz musimy jakoś zdobyć horrendalną sumę po prawej stronie znaku plus, aby pochłonąć
cn
lewą. Jeśli po prostu to związamy , otrzymamy z grubsza . Ale to jest za duże - nie ma miejsca na wyciskanie w dodatku . Rozwińmy więc sumę za pomocą wzoru szeregu arytmetycznego:2(1/n) ∑i=n/2 to n an
2(1/n)(n/2)an = an
cn
gdzie korzystamy z tego, że n jest „wystarczająco duży”, aby zastąpić brzydkie
floor(n/2)
czynniki znacznie czystszym (i mniejszym)n/4
. Teraz możemy kontynuowaćpod warunkiem
a > 16c
.To daje
T(n) = O(n)
. To jasneOmega(n)
, więc rozumiemyT(n) = Theta(n)
.źródło
k > length(A) - length(A2)
?A
naA1
iA2
wokół przegubu, wiemy, żelength(A) == length(A1)+length(A2)+1
. Jest więck > length(A)-length(A2)
równoważnek > length(A1)+1
, co jest prawdą, gdyk
jest gdzieś w środkuA2
.Szybkie Google na ten temat („k-ty największy zestaw elementów”) zwrócił to: http://discuss.joelonsoftware.com/default.asp?interview.11.509587.17
(to było specjalnie dla największych 3D)
i ta odpowiedź:
źródło
Lubisz quicksort. Wybierz element losowo i wepchnij wszystko wyżej lub niżej. W tym momencie będziesz wiedział, który element faktycznie wybrałeś, a jeśli jest to k-ty element, który zrobiłeś, w przeciwnym razie powtórzysz z binem (wyższym lub niższym), do którego wpadłby k-ty element. Mówiąc statystycznie, czas trzeba znaleźć, aby kth element wyrósł z n, O (n).
źródło
Companion Programisty do algorytm analizy daje wersję, która jest O (n), chociaż Autor stwierdza, że stały czynnik jest tak wysoka, że pewnie wolą naiwny sortowania-the-listy-then-wybierz metodę.
Odpowiedziałem na twoje pytanie :)
źródło
Standardowa biblioteka C ++ ma prawie dokładnie to wywołanie funkcji
nth_element
, chociaż modyfikuje dane. Oczekiwał liniowego czasu działania, O (N), a także dokonuje częściowego sortowania.źródło
Chociaż nie jestem bardzo pewny co do złożoności O (n), ale na pewno będzie między O (n) a nLog (n). Upewnij się także, że jesteś bliżej O (n) niż nLog (n). Funkcja jest napisana w Javie
źródło
Zaimplementowałem znalezienie kth minimum w n nieposortowanych elementach za pomocą programowania dynamicznego, a konkretnie metody turniejowej. Czas wykonania wynosi O (n + klog (n)). Zastosowany mechanizm jest wymieniony jako jedna z metod na stronie Wikipedii dotyczących algorytmu selekcji (jak wskazano w jednym z powyższych postów). Możesz przeczytać o algorytmie, a także znaleźć kod (java) na mojej stronie blogu Finding Kth Minimum . Dodatkowo logika może dokonywać częściowego uporządkowania listy - zwraca pierwszy K min (lub max) w czasie O (klog (n)).
Mimo że kod podał wynik k-tego minimum, można zastosować podobną logikę, aby znaleźć k-tego maksimum w O (klog (n)), ignorując wstępne prace wykonane w celu utworzenia drzewa turniejowego.
źródło
Możesz to zrobić w O (n + kn) = O (n) (dla stałej k) dla czasu i O (k) dla przestrzeni, śledząc k największych elementów, które widziałeś.
Dla każdego elementu w tablicy możesz zeskanować listę k największych i zastąpić najmniejszy element nowym, jeśli jest większy.
Priorytetowe rozwiązanie sterty Warrena jest jednak fajniejsze.
źródło
O(n log k)
... nadal degeneruje się do O (nlogn) w przypadku dużego k. Myślałam, że będzie działać dobrze dla małych wartości k jednakże ... być może szybciej niż niektóre inne algorytmy wymienione tutaj [???]Seksowny szybki wybór w Pythonie
źródło
a1 = [i for i in arr if i > arr[r]]
ia2 = [i for i in arr if i < arr[r]]
zwróci k-ty największy element.numpy.sort
fornumpy array
lubsorted
for) jest szybsze niż użycie tej ręcznej implementacji.Znajdź medianę tablicy w czasie liniowym, a następnie użyj procedury podziału dokładnie tak, jak w szybkim sortowaniu, aby podzielić tablicę na dwie części, wartości na lewo od mediany mniejsze (<) niż niż mediana i na prawo większe niż (>) mediana , to też można zrobić w czasie liniowym, teraz przejdź do tej części tablicy, w której znajduje się kth element, Teraz rekurencja staje się: T (n) = T (n / 2) + cn, co daje mi O (n) overal.
źródło
Poniżej znajduje się link do pełnej implementacji z dość obszernym wyjaśnieniem, jak działa algorytm znajdowania elementu Kth w niesortowanym algorytmie. Podstawową ideą jest podzielenie tablicy na partycje jak w QuickSort. Aby jednak uniknąć ekstremalnych przypadków (np. Gdy na każdym kroku wybierany jest najmniejszy element, tak że algorytm ulega degeneracji do czasu działania O (n ^ 2)), stosuje się specjalny wybór przestawny, zwany algorytmem mediany median. Całe rozwiązanie działa w czasie O (n) w najgorszym i przeciętnym przypadku.
Oto link do pełnego artykułu (chodzi o znalezienie Kth najmniejszego elementu, ale zasada jest taka sama w przypadku znalezienia Kth największego ):
Znajdowanie K-tego najmniejszego elementu w niesortowanej tablicy
źródło
Zgodnie z tym artykułem Znalezienie K-tej największej pozycji na liście n pozycji,
O(n)
w najgorszym przypadku potrzebny będzie następujący algorytm .Analiza: zgodnie z sugestią w oryginalnym artykule:
Dlaczego rozmiar partycji jest brany 5, a nie 3?
Jak wspomniano w oryginalnym artykule :
Teraz próbowałem zaimplementować powyższy algorytm jako:
Dla uproszczenia inny algorytm korzysta z kolejki priorytetowej i zajmuje dużo czasu
O(nlogn)
.Oba te algorytmy można przetestować jako:
Zgodnie z oczekiwaniami dane wyjściowe to:
18 18
źródło
Co powiesz na to podejście?
Zachowaj a
buffer of length k
i atmp_max
, otrzymywanie tmp_max to O (k) i jest wykonywane n razy, więc coś w styluO(kn)
Czy to prawda, czy coś mi brakuje?
Mimo, że nie jest to średni przypadek szybkiego wyboru i najgorszy przypadek mediany statystyki, to jest dość łatwy do zrozumienia i wdrożenia.
źródło
iteruj po liście. jeśli bieżąca wartość jest większa niż zapisana największa wartość, zapisz ją jako największą wartość i podbij 1-4 w dół, a 5 spadnie z listy. Jeśli nie, porównaj go z numerem 2 i zrób to samo. Powtórz, sprawdzając względem wszystkich 5 zapisanych wartości. powinno to zrobić w O (n)
źródło
chciałbym zasugerować jedną odpowiedź
jeśli weźmiemy pierwsze k elementów i posortujemy je w połączoną listę wartości k
teraz dla każdej innej wartości, nawet w najgorszym przypadku, jeśli wykonujemy sortowanie wstawiania dla pozostałych wartości nk, nawet w najgorszym przypadku liczba porównań będzie k * (nk), a dla poprzednich sortowanych wartości k niech będzie to k * (k- 1) więc wychodzi na to, że jest (nk-k), co oznacza o (n)
Twoje zdrowie
źródło
Wyjaśnienie algorytmu median of of medians w celu znalezienia k-tej największej liczby całkowitej spośród n można znaleźć tutaj: http://cs.indstate.edu/~spitla/presentation.pdf
Implementacja w c ++ jest poniżej:
źródło
Istnieje również algorytm wyboru Wirtha , który ma prostszą implementację niż QuickSelect. Algorytm wyboru Wirtha jest wolniejszy niż QuickSelect, ale z pewnymi ulepszeniami staje się szybszy.
Bardziej szczegółowo. Korzystając z optymalizacji MODIFIND Vladimira Zabrodsky'ego i wyboru środkowej z 3 osi obrotu oraz zwracając uwagę na końcowe kroki partycjonowania części algorytmu, opracowałem następujący algorytm (prawdopodobnie o nazwie „LefSelect”):
W testach porównawczych, które tutaj zrobiłem , LefSelect jest o 20-30% szybszy niż QuickSelect.
źródło
Rozwiązanie Haskell:
To implementuje medianę rozwiązań medianowych za pomocą metody withShape w celu wykrycia rozmiaru partycji bez jej obliczania.
źródło
Oto implementacja C ++ Randomized QuickSelect. Chodzi o to, aby losowo wybrać element przestawny. Aby zaimplementować losową partycję, używamy funkcji losowej, rand (), aby wygenerować indeks między l i r, zamienić element w losowo wygenerowanym indeksie na ostatni element, i na koniec wywołać standardowy proces partycjonowania, który używa ostatniego elementu jako elementu przestawnego.
Złożoność powyższego rozwiązania w najgorszym przypadku to nadal O (n2). W najgorszym przypadku funkcja losowa może zawsze wybrać element narożny. Oczekiwana złożoność czasowa powyższej randomizowanej funkcji QuickSelect wynosi Θ (n)
źródło
Wywołanie ankiety () k razy.
źródło
To jest implementacja w Javascript.
Jeśli zwolnisz ograniczenie, że nie możesz zmodyfikować tablicy, możesz zapobiec wykorzystaniu dodatkowej pamięci, używając dwóch indeksów do identyfikacji „bieżącej partycji” (w klasycznym stylu Quicksort - http://www.nczonline.net/blog/2012/ 11/27 / computer-science-in-javascript-quicksort / ).
Jeśli chcesz przetestować jego działanie, możesz użyć tej odmiany:
Reszta kodu polega na stworzeniu placu zabaw:
Teraz uruchom kilka testów. Z powodu Math.random () będzie generować za każdym razem inne wyniki:
Jeśli przetestujesz go kilka razy, zobaczysz nawet empirycznie, że liczba iteracji wynosi średnio O (n) ~ = stała * n, a wartość k nie wpływa na algorytm.
źródło
Wymyśliłem ten algorytm i wygląda na O (n):
Powiedzmy, że k = 3 i chcemy znaleźć trzeci co do wielkości element w tablicy. Utworzyłbym trzy zmienne i porównałbym każdy element tablicy z minimum tych trzech zmiennych. Jeśli element tablicy jest większy niż nasze minimum, zmienilibyśmy zmienną min na wartość elementu. Kontynuujemy to samo do końca tablicy. Minimum trzech naszych zmiennych to 3. co do wielkości pozycja w tablicy.
Aby znaleźć Kth największy przedmiot, potrzebujemy zmiennych K.
Przykład: (k = 3)
Czy ktoś może to przejrzeć i dać mi znać, czego mi brakuje?
źródło
Oto implementacja zaproponowanego przez eladv algorytmu (tutaj też umieszczam implementację z losową osią przestawną):
źródło
jest podobny do strategii quickSort, w której wybieramy dowolną oś obrotu i umieszczamy mniejsze elementy po lewej, a większe po prawej
źródło
Idź do końca tego linku: ...........
http://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-3-worst-case-linear-time/
źródło
Można znaleźć k-ty najmniejszy element w czasie O (n) i stałej przestrzeni. Jeśli weźmiemy pod uwagę, tablica jest tylko dla liczb całkowitych.
Podejście polega na przeszukaniu binarnym zakresu wartości tablicy. Jeśli mamy wartość min_value i max_value w zakresie liczb całkowitych, możemy przeprowadzić wyszukiwanie binarne w tym zakresie. Możemy napisać funkcję komparatora, która powie nam, czy jakakolwiek wartość jest k-najmniejsza lub mniejsza niż k-ta najmniejsza lub większa niż k-ta najmniejsza. Wykonuj wyszukiwanie binarne, aż dojdziesz do k-tej najmniejszej liczby
Oto kod do tego
rozwiązanie klasy:
źródło
Istnieje również jeden algorytm, który przewyższa algorytm szybkiego wyboru. Nazywa się to algorytmem Floyd-Rivets (FR) .
Artykuł oryginalny: https://doi.org/10.1145/360680.360694
Wersja do pobrania: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.309.7108&rep=rep1&type=pdf
Artykuł w Wikipedii https://en.wikipedia.org/wiki/Floyd%E2%80%93Rivest_algorithm
Próbowałem zaimplementować algorytm szybkiego wyboru i FR w C ++. Porównałem je również do standardowych implementacji biblioteki C ++ std :: nth_element (która jest w zasadzie hybrydą hybrydową szybkiego wyboru i heapseleksu). Wynik był szybki i nth_element działał średnio średnio, ale algorytm FR działał około. dwa razy szybciej w porównaniu do nich.
Przykładowy kod, którego użyłem dla algorytmu FR:
źródło
Chciałbym to zrobić:
Możesz po prostu przechowywać wskaźniki do pierwszego i ostatniego elementu na połączonej liście. Zmieniają się one tylko po dokonaniu aktualizacji listy.
Aktualizacja:
źródło
Najpierw możemy zbudować BST z nieposortowanej tablicy, która zajmuje O (n) czasu, a z BST możemy znaleźć k-ty najmniejszy element w O (log (n)), który w sumie liczy się do rzędu O (n).
źródło