Zapytano mnie o to w wywiadzie i oto rozwiązanie, które podałem:
public static int[] merge(int[] a, int[] b) {
int[] answer = new int[a.length + b.length];
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length)
{
if (a[i] < b[j])
{
answer[k] = a[i];
i++;
}
else
{
answer[k] = b[j];
j++;
}
k++;
}
while (i < a.length)
{
answer[k] = a[i];
i++;
k++;
}
while (j < b.length)
{
answer[k] = b[j];
j++;
k++;
}
return answer;
}
Czy istnieje skuteczniejszy sposób na zrobienie tego?
Edycja: poprawione metody długości.
while (i < a.length && j < b.length) answer[k++] = a[i] < b[j] ? a[i++] : b[j++];
Specyfikacja języka Java: operator warunkowy? : .Odpowiedzi:
Niewielkie ulepszenie, ale po zakończeniu pętli głównej możesz użyć
System.arraycopy
do skopiowania końca jednej z tablic wejściowych, gdy dojdziesz do końca drugiej. Nie zmieni to jednakO(n)
charakterystyki wydajności Twojego rozwiązania.źródło
Jest trochę bardziej kompaktowy, ale dokładnie taki sam!
źródło
Dziwię się, że nikt nie wspomniał o tej znacznie fajniejszej, wydajniejszej i kompaktowej implementacji:
Punkty zainteresowania
System.arraycopy
, ponieważ wewnętrznie może to zrobić za pomocą jednej instrukcji asemblera x86.a[i] >= b[j]
zamiasta[i] > b[j]
. Gwarantuje to "stabilność", która jest definiowana tak, że gdy elementy a i b są równe, chcemy elementów z a przed b.źródło
j < 0
,b
jest już wyczerpany, więc nadal dodajemy pozostałea
elementy doanswer
tablicyWszelkie ulepszenia, które można by wprowadzić, byłyby mikro-optymalizacjami, ogólny algorytm jest poprawny.
źródło
System.arrayCopy()
jest głupio szybki, ponieważ wykorzystujememcpy
wywołania zoptymalizowane pod kątem procesora . Istnieje więc możliwość poprawy wydajności poprzez kopiowanie fragmentów. Istnieje również możliwość binarnego wyszukiwania granic.To rozwiązanie jest również bardzo podobne do innych postów z tym wyjątkiem, że używa System.arrayCopy do kopiowania pozostałych elementów tablicy.
źródło
Oto zaktualizowana funkcja. Usuwa duplikaty, miejmy nadzieję, że ktoś uzna to za przydatne:
źródło
Można to zrobić w 4 stwierdzeniach, jak poniżej
źródło
sort
funkcja nie może używać siebie jako metody sortowania. To byłaby nieskończona regresja zamiast rekurencji. Inną przesłanką jest to, że merge_array jest funkcją implementującą sort. Zatem ta odpowiedź jest bezużyteczna w najbardziej prawdopodobnym kontekście.Musiałem to napisać w javascript, oto jest:
źródło
Kolekcje Apache obsługują metodę sortowania od wersji 4; możesz to zrobić za pomocą
collate
metody w:Oto cytat z javadoc:
Nie wymyślaj koła na nowo! Referencje dokumentu: http://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html
źródło
GallopSearch Merge: O (log (n) * log (i)) zamiast O (n)
Poszedłem do przodu i zastosowałem sugestię siwobrodego w komentarzach. Głównie dlatego, że potrzebowałem wysoce wydajnej wersji tego kodu o znaczeniu krytycznym.
Powinien to być najbardziej efektywny sposób, aby to zrobić, ze złożonością czasową O (log (n) * log (i)) zamiast O (n). I w najgorszym przypadku złożoność czasowa O (n). Jeśli twoje tablice są zlepione i mają razem długie ciągi wartości, będzie to przyćmić każdy inny sposób, w przeciwnym razie będzie po prostu lepszy od nich.
Ma dwie wartości odczytu na końcach tablicy scalającej i wartość zapisu w tablicy wyników. Po ustaleniu, która wartość końcowa jest mniejsza, wykonuje galopowe przeszukiwanie tej tablicy. 1, 2, 4, 8, 16, 32 itd. Gdy znajdzie zakres, w którym wartość odczytu drugiej tablicy jest większa. Przeszukuje binarnie w tym zakresie (przecina zakres o połowę, przeszukuje właściwą połowę, powtarza do pojedynczej wartości). Następnie tablica kopiuje te wartości do pozycji zapisu. Należy pamiętać, że kopia jest z konieczności przenoszona w taki sposób, że nie może nadpisać tych samych wartości z obu tablic odczytujących (co oznacza, że tablica zapisu i tablica odczytu mogą być takie same). Następnie wykonuje tę samą operację dla drugiej tablicy, o której wiadomo, że jest mniejsza niż nowa odczytana wartość drugiej tablicy.
Powinien to być najbardziej efektywny sposób, aby to zrobić.
Niektóre odpowiedzi miały zduplikowaną możliwość usuwania. Będzie to wymagało algorytmu O (n), ponieważ musisz faktycznie porównać każdy element. Więc tutaj jest osobna, do zastosowania po fakcie. Nie możesz galopować przez wiele wpisów do końca, jeśli chcesz spojrzeć na wszystkie z nich, chociaż możesz galopować przez duplikaty, jeśli masz ich dużo.
Aktualizacja: poprzednia odpowiedź, nie okropny kod, ale wyraźnie gorszy od powyższego.
Kolejna niepotrzebna hiperoptymalizacja. Nie tylko wywołuje arraycopy dla bitów końcowych, ale także dla początku. Przetwarzanie dowolnego wprowadzającego nienakładania się w O (log (n)) przez wyszukiwanie binarne w danych. O (log (n) + n) jest O (n) iw niektórych przypadkach efekt będzie dość wyraźny, szczególnie w sytuacjach, gdy w ogóle nie ma nakładania się między scalanymi tablicami.
źródło
That is totally what the implemented Arrays.sort does
( To : z pierwszej rewizji Twojej odpowiedzi - lub - z mojego komentarza z 19 lutego?) - nie możesz znaleźć ani w JDK 8 firmy Sunsoft: do której implementacjiArrays.sort
się odnosisz?Oto skrócony formularz napisany w javascript:
źródło
źródło
a[mid+1 .. hi]
doaux
za?Myślę, że wprowadzenie listy pominięć dla większej posortowanej tablicy może zmniejszyć liczbę porównań i przyspieszyć proces kopiowania do trzeciej tablicy. Może to być dobre, jeśli tablica jest zbyt duża.
źródło
źródło
źródło
for (int i, j, k = i = j = 0 ; k < c.length ; ) c[k++] = b.length <= j || i < a.length && a[i] < b[j] ? a[i++] : b[j++];
. Czym się to różni od odpowiedzi Andrew z 2014 roku ?Algorytm można ulepszyć na wiele sposobów. Na przykład rozsądne jest sprawdzenie, czy
a[m-1]<b[0]
lubb[n-1]<a[0]
. W żadnym z tych przypadków nie ma potrzeby wykonywania więcej porównań. Algorytm mógłby po prostu skopiować tablice źródłowe w wynikowej we właściwej kolejności.Bardziej skomplikowane ulepszenia mogą obejmować wyszukiwanie elementów przeplatających i uruchamianie algorytmu scalania tylko dla nich. Może to zaoszczędzić dużo czasu, gdy rozmiary scalonych tablic różnią się dziesiątkami razy.
źródło
Ten problem jest związany z algorytmem scalania, w którym dwie posortowane pod-tablice są łączone w jedną posortowaną pod-tablicę. W CLR książka daje przykład algorytmu i czyści konieczność sprawdzenia, czy koniec został osiągnięty przez dodanie wartości wskaźnikowych (coś, porównuje i „większy niż jakiejkolwiek innej wartości”) na końcu każdej tablicy.
Napisałem to w Pythonie, ale powinno też ładnie przełożyć się na Javę:
źródło
Możesz użyć 2 wątków, aby wypełnić wynikową tablicę, jeden z przodu, jeden z tyłu.
Może to działać bez synchronizacji w przypadku liczb, np. Jeśli każdy gwint wstawia połowę wartości.
źródło
źródło
źródło
źródło
Moim ulubionym językiem programowania jest JavaScript
źródło
Może użyj System.arraycopy
źródło
Wynik to:
1, 2, 3, 4, 5, 6, 8, 9, 10, 100, 999, 1001,
źródło
arr2
nieind2
, aletemp
.Możesz użyć operatorów trójskładnikowych, aby kod był nieco bardziej zwarty
źródło
Tylko trochę różni się od oryginalnego rozwiązania
źródło
Aby zaznaczyć dwie posortowane tablice w złożoności czasowej O (m + n), użyj poniższego podejścia z tylko jedną pętlą. m i n to długość pierwszej tablicy i drugiej tablicy.
źródło
źródło
Ponieważ pytanie nie zakłada żadnego konkretnego języka. Oto rozwiązanie w Pythonie. Zakładając, że tablice są już posortowane.
Podejście 1 - używanie tablic numpy: import numpy
Podejście 2 - Używając listy, zakładając, że listy są sortowane.
źródło
Since the question doesn't assume any specific language
od 2011/5/11/19: 43, jest otagowany java ..sort()
jestO(n log n)
w najlepszym przypadkuOto moja implementacja java, która usuwa duplikaty.
źródło