„Prawie sortujące” liczby całkowite w czasie liniowym

16

Interesuje mnie sortowanie tablicy dodatnich wartości liczb całkowitych w czasie liniowym (w modelu pamięci RAM z jednolitą miarą kosztów, tj. Liczby całkowite mogą mieć wielkość logarytmiczną, ale przyjmuje się, że operacje arytmetyczne na nich przyjmą czas jednostkowy). Oczywiście nie jest to możliwe w przypadku algorytmów sortowania opartych na porównaniu, więc jestem zainteresowany obliczeniem sortowania „przybliżonego”, tj. Obliczeniem pewnej permutacji z , która tak naprawdę nie jest klasyfikowane w ogóle, ale „dobrym przybliżeniem” z posortowanej wersji L . Zakładam, że sortujemy liczby całkowite w malejącej kolejności, ponieważ sprawia to, że kontynuacja jest nieco przyjemniejsza w stwierdzeniu, ale oczywiście można by sformułować problem na odwrót.L=v1,,vnvσ(1),,vσ(n)LL

Jednym z możliwych kryteriów przybliżonego sortowania jest (*): pozwalając N być ivi , dla każdego 1in , wymagamy, aby vσ(i)N/i (tj. lista „quasi-posortowana” jest ograniczona od góry przez malejącą funkcję iN/i ). Łatwo zauważyć, że faktyczny sort spełnia to: vσ(2) może być większy niż vσ(1) więc jest co najwyżej (vσ(1)+vσ(2))/2 czyli N/2 , i ogólnie vσ(i) może być większy niż (jivσ(i))/i który jest N/i.

Na przykład wymaganie (*) można osiągnąć za pomocą poniższego algorytmu (sugerowanego przez @Louis). Moje pytanie brzmi: czy istnieją prace nad tym zadaniem „prawie sortowania” liczb całkowitych w czasie liniowym, poprzez nałożenie jakiegoś wymogu, takiego jak (*), który spełniłby prawdziwy sort? Czy poniższy algorytm lub jego wariant ma ustaloną nazwę?

Edycja: poprawiono algorytm i dodano więcej wyjaśnień


Algorytm:

INPUT: V an array of size n containing positive integers
OUTPUT: T

N = Σ_{i<n} V[i]
Create n buckets indexed by 1..n
For i in 1..n
| Add V[i] into the bucket min(floor(N/V[i]),n)
+

For bucket 1 to bucket n
| For each element in the bucket
| | Append element to T
| +
+

Ten algorytm działa zgodnie z przeznaczeniem z następujących powodów:

  1. Jeśli element znajduje się w wiadrze wówczas . vjvN/j

    v jest wstawiane do wiadra , a zatem j ≤ \ lfloor N / v \ rfloor ≤ N / vj=min(N/v,n)jN/vN/v

  2. Jeśli element znajduje się w wiadrze albo lub . vjN/(j+1)<vj=n

    vj = min ( N / v , n ) j = N / v j = n j = N / v j N / v < j + 1 N / ( j + 1 ) < v jest wstawiane do segmentu , a zatem lub . W pierwszym przypadku co oznacza a zatem .j=min(N/v,n)j=N/vj=nj=N/vjN/v<j+1N/(j+1)<v

  3. Dla istnieje najwyżej elementów w wiadrach od 1 do .j<njj

    Niech i niech będzie całkowitą liczbą elementów w jednym z segmentów 1..j. Do 2. mamy, że każdy element w segmencie (z ) jest taki, że . Dlatego suma wszystkich elementów w segmentach od do jest większa niż . Ale ta suma jest również mniejsza niż zatem a zatem co daje nam lub .j<nkviijN/(j+1)N/(i+1)<vK1jk×N/(J+1)KNk×N/(j+1)<KNk/(j+1)<1k<j+1kj

  4. T spełnia (*) tj. -ty element jest taki, żejTT[j]N/j

    Do 3. mamy, że , ty element , pochodzi z wiadra z dlatego .T[j]jTiijT[j]N/iN/j

  5. Algorytm ten zajmuje czas liniowy.

    Obliczenie zajmuje czas liniowy. Wiadra mogą być implementowane za pomocą połączonej listy, która ma wstawianie i iterację . Zagnieżdżona pętla działa tyle razy, ile jest elementów (tj. razy).NO(1)n

a3nm
źródło
1
Nie odrzucać pytania (+1, to dobre), ale czy sortowanie radix nie zrobiłoby więcej, niż potrzebujesz?
user541686 24.04.17
@Mehrdad: Dziękujemy za komentarz! Sortowanie za pomocą Radix posortowałoby liczby całkowite, ale zajęłoby to czas . O(nlog(maxivi))
ann
Czy mógłbyś skomentować, co dokładnie jest niepożądane w tej złożoności czasu? Czy masz jedną bardzo dużą liczbę całkowitą, a wszystko inne jest na przykład małe?
user541686,
1
@ a3nm sortowanie radix nie jest O (n log n), jest O (n), a zatem liniowe, jeśli rozmiar liczb całkowitych jest stały, na przykład liczby 32-bitowe lub liczby 64-bitowe. Czy sortowane liczby mają zmienny rozmiar?
Xavier Combelle
1
@XavierCombelle: Tak, pracuję w modelu RAM i nie mogę przypuszczać, że wejściowe liczby całkowite są ograniczone stałą.
a3nm

Odpowiedzi:

8

Brzmi to bardzo podobnie do algorytmu ASort. Zobacz ten artykuł autorstwa Giesen i in. glin.:

https://www.inf.ethz.ch/personal/smilos/asort3.pdf

Niestety czas działania nie jest dość liniowy. Powyższy artykuł dowodzi, że dowolny oparty na porównaniu algorytm losowy algorytm uszeregujący elementów w obrębie n 2 / ν ( n ) ma dolną granicę n l o g ( ν ( n ) ) (przy założeniu ν ( n ) < n ).nn2/ν(n)nlog(ν(n))ν(n)<n


EDYTUJ , w odpowiedzi na wyjaśnienia w pytaniu:

To, co robisz, to po prostu rodzaj wiadra . Jednak algorytm sortowania segmentowego nie jest w tym przypadku liniowy. Problem: musisz zsumować liczby naturalne, a następnie wykonać podział na każdym z nich. Ponieważ liczby są nieograniczone pod względem wielkości, nie jest już operacją o stałym czasie. Wykonanie większej liczby liczb będzie wymagało więcej czasu.N/V[i]

Jak długo jeszcze? Dzielenie zależy od liczby cyfr, więc jest to , razy n operacji dzielenia. To chyba brzmi znajomo. :)lg(n)n

Trixie Wolf
źródło
1
Dziękujemy za wskazanie nam tego artykułu! Rzeczywiście jest to trochę związane z pytaniem. Jednak mój algorytm (ani wersja oryginalna, ani nieco inna wersja poprawiona) nie jest tak podobny do ASort ;. Po pierwsze, uważam, że mój algorytm działa w , a nie w czasie superlinearnym, jak ASort. Po drugie, kryterium (*) jest całkiem inne niż przybliżenie odległości kroków Spearmana; np. kryterium (*) jest mniej lub bardziej ścisłe w zależności od wartości liczb całkowitych, w przeciwieństwie do odległości w stopach. Po trzecie, mimo że zarówno nasz algorytm, jak i ASort są elementami segmentującymi, kryteria są całkiem inne. O(n)
a3nm
@ a3nm Wyjaśnienie tego, co opublikowałeś powyżej, sugeruje, że używasz sortowania kubełkowego , który jest liniowy (a nie oparty na porównaniu, co oznacza testowanie dwóch elementów ze sobą). Problem polega na tym, że nie działa dla wszystkich liczb matematycznych. Działa tylko wtedy, gdy rozmiar liczby całkowitej jest ograniczony.
Trixie Wolf
Kiedy mówisz „Działa to tylko, gdy rozmiar liczby całkowitej jest ograniczony”, myślę, że jest to prawdą tylko wtedy, gdy faktycznie sortowałem liczby całkowite. Ale ogólnie algorytm, który opublikowałem, tak naprawdę ich nie sortuje, tylko wymusza słabsze kryterium (*). Myślę więc, że działa w czasie liniowym, nawet gdy rozmiar liczby całkowitej nie jest ograniczony.
a3nm
2
@ a3nm To nie jest liniowe. Zobacz moją rozszerzoną odpowiedź powyżej.
Trixie Wolf
Dzięki za odpowiedź i przepraszam za opóźnienie. Myślę, że jest pewien zamieszanie w modelu. Pracuję w modelu RAM z jednolitym pomiarem czasu (jak w van Emde Boas, Modele maszyn i symulacje, w Podręczniku obliczeń): więc liczby, którymi manipuluję, mogą mieć rozmiar logarytmiczny, ale operacje arytmetyczne na tych liczbach mają koszt jednostkowy. Zredagowałem odpowiednio moje pytanie. Myślę, że w tym modelu algorytm, który proponuję, działa naprawdę w czasie liniowym (ale oczywiście w tym modelu nadal obowiązuje dolna granica dla rzeczywistego sortowania na podstawie porównania). nlogn
a3nm
2

Jak się okazuje, moje pytanie jest jednak zupełnie nieistotne. Rzeczywiście, pracuję na maszynie RAM z jednolitą miarą kosztów (tj. Mamy rejestry, których rejestry niekoniecznie muszą mieć stały rozmiar, ale mogą przechowywać na wejściu liczby całkowite o wielkości logarytmicznej, a operacje na tych rejestrach zajmują stały czas, w tym przynajmniej dodatek). W rzeczywistości w tym modelu sortowanie liczb całkowitych (przez zasadniczo wykonanie sortowania radix) może odbywać się w czasie liniowym. Wyjaśnia to w artykule z 1996 r. Grandjean, Sortowanie, czas liniowy i problem satysfakcji .

(To nie odpowiada na moje pytanie, czy istnieją dobrze zbadane pojęcia „prawie sortowania” zestawu liczb całkowitych, ale aby były interesujące, prawdopodobnie potrzebne byłyby te słabsze pojęcia, aby były łatwiejsze do wyegzekwowania, tj. Praca nad słabszym model lub w jakiś sposób uruchomić w czasie podliniowym. Jednak obecnie nie jestem świadomy sensu, w którym by tak było).

a3nm
źródło