2011-11-29 12 views
22

Wiele algorytmów działa przy użyciu merge algorithm, aby scalić dwie różne posortowane tablice w jedną posortowaną tablicę. Przykładowo, jeżeli na wejściu tabliceAlgorytm scalania pamięci i adaptacji?

1 3 4 5 8 

i

2 6 7 9 

Przejęcie tych tablic byłby Array

1 2 3 4 5 6 7 8 9 

Tradycyjnie, wydaje się, że dwa różne podejścia do łączenia posortowane tablice (zwróć uwagę, że przypadek łączenia połączonych list jest zupełnie inny). Po pierwsze, istnieją algorytmy scalania out-of-place, które działają poprzez przydzielenie tymczasowego bufora do przechowywania, a następnie przechowywanie wyniku scalenia w tymczasowym buforze. Po drugie, jeśli te dwie macierze są częścią tej samej macierzy wejściowej, są in-place merge algorithms, które wykorzystują tylko O ​​(1) dodatkową przestrzeń pamięci i zmieniają dwie sąsiadujące sekwencje w jedną posortowaną sekwencję. Te dwie klasy algorytmów działają w czasie O (n), ale algorytm łączenia poza miejscem ma zwykle znacznie niższy stały współczynnik, ponieważ nie ma tak rygorystycznych wymagań dotyczących pamięci.

Moje pytanie brzmi, czy istnieje znany algorytm łączenia, który może "interpolować" pomiędzy tymi dwoma podejściami. Oznacza to, że algorytm używałby gdzieś pomiędzy pamięcią O (1) i O (n), ale im więcej pamięci ma do dyspozycji, tym szybciej działa. Na przykład, gdybyśmy mieli zmierzyć bezwzględną liczbę odczytów/zapisów tablic wykonywanych przez algorytm, może on mieć środowisko wykonawcze w postaci ng (s) + f (s), gdzie s jest ilością dostępnej dla niego przestrzeni i g (s) i f (s) są funkcjami uzyskanymi z dostępnej przestrzeni. Zaletą tej funkcji jest to, że może ona próbować scalić dwie tablice w najbardziej efektywny sposób z uwzględnieniem ograniczeń pamięci - im więcej pamięci jest dostępnej w systemie, tym więcej pamięci z niej korzysta i (najlepiej) tym lepsza wydajność, jaką miałaby .

Bardziej formalnie algorytm powinien działać w następujący sposób. Jako dane wejściowe podaje się tablicę A składającą się z dwóch sąsiednich, posortowanych zakresów, zmieniających rozmieszczenie elementów w tablicy tak, aby elementy były całkowicie posortowane według kolejności. Algorytm może wykorzystywać przestrzeń zewnętrzną, a jej wydajność powinna być najgorszym przypadkiem O (n) we wszystkich przypadkach, ale powinna przebiegać progresywnie szybciej, biorąc pod uwagę większą ilość przestrzeni pomocniczej do wykorzystania.

Czy ktoś zna algorytm tego rodzaju (lub wie gdzie szukać, aby znaleźć opis jednego?)

+1

http://stackoverflow.com/questions/3156599/merge-two-sorted-parts-of-an-array-with-constant-memory-in-on-on- – necromancer

+0

@ agksmehx- Dzięki za link. Jednak nie sądzę, że jest to dokładnie to, czego szukam.Jestem już świadomy, że możesz scalić O (1) dodatkową przestrzeń, a to pytanie jest głównie pytaniem, czy istnieje sposób na algorytm scalania, który stopniowo zwiększa się, dając więcej wolnej przestrzeni, którą ci dajesz, tak abyś mógł otrzymasz, powiedzmy, 100 MB dodatkowej przestrzeni na 500 MB danych, scaliłbyś się szybciej niż gdybyś miał 10 MB na 500 MB danych. – templatetypedef

+0

Jakie są wejścia i wyjścia? Czy piszecie do jednej z tablic wejściowych lub do osobnej tablicy? (Podejrzewam, że to pierwsze, bo jeśli to drugie, to nie jest problem.) – MSN

Odpowiedz

10

przynajmniej zgodnie z dokumentacją The in-place merge function in SGI STL jest adaptacyjne i „jego run-time złożoność zależy o ilości dostępnej pamięci ". Kod źródłowy jest oczywiście dostępny, możesz przynajmniej sprawdzić ten.

+0

Chociaż to na pewno działa, zauważ, że ta funkcja w najgorszym przypadku ulega degradacji do O (n log n), podczas gdy istnieją najgorsze algorytmy scalania O (n) w miejscu. Mam nadzieję, że jest coś lepszego niż to, chociaż O (n log n) jest nadal bardzo dobre. – templatetypedef

2

EDYCJA: STL ma inplace_merge, który dostosuje się do rozmiaru dostępnego tymczasowego bufora. Jeśli bufor tymczasowy jest co najmniej tak duży, jak jeden z pod-tablic, jest to O (N). W przeciwnym razie dzieli scalenie na dwie podgrupy i rekurencje. Podział bierze O (log N), aby znaleźć właściwą część innej podkanałów do obrócenia (wyszukiwanie binarne).

Przechodzi z O (N) do O (N log N) w zależności od ilości dostępnej pamięci.

+0

Podczas gdy to na pewno zadziała, ma ono patologiczne zachowanie, gdy wszystkie elementy w 'lhs' są większe niż najmniejszy element w' rhs'. Na przykład tablica taka jak '[5, 6, 7, 8, 9, 0, 1, 2, 3, 4]'. W takich przypadkach twój algorytm staje się "kopiować' T "z' rhs' na 'temp', przesuwać' lhs' w dół o pozycje 'T', kopiować' T' przedmiotów z 'temp' do nowo utworzonej przestrzeni '. do zrobienia '(sizeof (lhs) * sizeof (rhs))/T' porusza się wewnątrz macierzy, plus' 2 * (sizeof (rhs)/T) przesuwa się z tablicy do temp iz powrotem. Algorytm to O (n^2), jak widać, jeśli 'T == 1'. –

+0

@ JimMischel, nie, nie porusza' lhs', to kopiowanie z przodu 'lhs' do przestrzeni pozostawionej przez' rhs'. skopiuj każdy element z 'lhs' co najwyżej dwa razy, nie przesuwajmy tablicy, po prostu wielokrotnie okręcaj początek dookoła końca Gdybyśmy przenieśli' lhs', byłby to N^2. Właśnie dlatego kopiujemy dane mamy zamiar zastąpić zamiast przenosić całą tablicę – MSN

+0

Dlaczego usunąłeś swój drugi algorytm? Czy było to zbyt skomplikowane, a faktyczny algorytm okazał się prosty? –