[英]How to sort in-place using the merge sort algorithm?
我知道這個問題不太具體。
我想要的只是有人告訴我如何將普通合並排序轉換為就地合並排序(或具有恆定額外空間開銷的合並排序)。
我能找到的(在網上)只有頁面說“它太復雜了”或“超出了本文的范圍”。
就地合並(沒有任何額外空間)的唯一已知方法太復雜,無法簡化為實際程序。 (取自這里)
即使它太復雜了,如何進行就地歸並排序的基本概念是什么?
Knuth 將此作為練習(第 3 卷,5.2.5)。 確實存在就地合並排序。 它們必須認真執行。
首先,像這里描述的那樣幼稚的就地合並不是正確的解決方案。 它將性能降級到O(N 2 ) 。
這個想法是對數組的一部分進行排序,同時將其余部分用作合並的工作區域。
例如像下面的合並函數。
void wmerge(Key* xs, int i, int m, int j, int n, int w) {
while (i < m && j < n)
swap(xs, w++, xs[i] < xs[j] ? i++ : j++);
while (i < m)
swap(xs, w++, i++);
while (j < n)
swap(xs, w++, j++);
}
它采用數組xs
,兩個排序的子數組分別表示為范圍[i, m)
和[j, n)
。 工作區從w
開始。 與大多數教科書中給出的標准合並算法相比,該算法在排序后的子數組和工作區之間交換內容。 結果,前一個工作區包含合並后的排序元素,而前一個工作區中存儲的元素被移動到兩個子數組中。
但是,必須滿足兩個約束條件:
定義了這個合並算法,很容易想象一個解決方案,它可以對數組的一半進行排序; 接下來的問題是,如何處理工作區中剩余的未排序部分,如下圖所示:
... unsorted 1/2 array ... | ... sorted 1/2 array ...
一個直觀的想法是對另一半工作區進行遞歸排序,因此只有 1/4 元素尚未排序。
... unsorted 1/4 array ... | sorted 1/4 array B | sorted 1/2 array A ...
這個階段的關鍵是我們遲早必須將已排序的 1/4 元素 B 與已排序的 1/2 元素 A 合並。
剩下的工作區是否只有 1/4 個元素,大到足以合並 A 和 B? 不幸的是,事實並非如此。
但是,上面提到的第二個約束給了我們一個提示,如果我們可以確保未合並的元素不會被覆蓋的合並順序,我們可以通過將工作區與任一子數組重疊來利用它。
實際上,我們可以對前半部分進行排序,而不是對工作區的后半部分進行排序,並將工作區放在兩個已排序的數組之間,如下所示:
... sorted 1/4 array B | unsorted work area | ... sorted 1/2 array A ...
這種設置有效地安排了與子陣列 A 重疊的工作區。 [Jyrki Katajainen, Tomi Pasanen, Jukka Teuhola. ``實用的就地歸並排序''。 北歐計算雜志,1996 年]。
所以剩下的就是重復上面的步驟,將工作區域從1/2、1/4、1/8,……當工作區域變得足夠小(比如只剩下兩個元素)時,我們可以切換到一個簡單的插入排序來結束這個算法。
這是基於本文的 ANSI C 實現。
void imsort(Key* xs, int l, int u);
void swap(Key* xs, int i, int j) {
Key tmp = xs[i]; xs[i] = xs[j]; xs[j] = tmp;
}
/*
* sort xs[l, u), and put result to working area w.
* constraint, len(w) == u - l
*/
void wsort(Key* xs, int l, int u, int w) {
int m;
if (u - l > 1) {
m = l + (u - l) / 2;
imsort(xs, l, m);
imsort(xs, m, u);
wmerge(xs, l, m, m, u, w);
}
else
while (l < u)
swap(xs, l++, w++);
}
void imsort(Key* xs, int l, int u) {
int m, n, w;
if (u - l > 1) {
m = l + (u - l) / 2;
w = l + u - m;
wsort(xs, l, m, w); /* the last half contains sorted elements */
while (w - l > 2) {
n = w;
w = l + (n - l + 1) / 2;
wsort(xs, w, n, l); /* the first half of the previous working area contains sorted elements */
wmerge(xs, l, l + n - w, n, u, w);
}
for (n = w; n > l; --n) /*switch to insertion sort*/
for (m = n; m < u && xs[m] < xs[m-1]; ++m)
swap(xs, m, m - 1);
}
}
wmerge 之前定義的地方。
順便說一下,這個版本不是最快的歸並排序,因為它需要更多的交換操作。 根據我的測試,它比標准版本更快,標准版本在每次遞歸中分配額外的空間。 但它比優化版本慢,優化版本提前將原始數組加倍並用於進一步合並。
包括其“大結果”,本文描述了就地歸並排序 (PDF) 的幾個變體:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.22.5514&rep=rep1&type=pdf
移動較少的就地排序
於爾基·卡塔雅寧,托米·A·帕薩寧
結果表明,可以使用 O(1) 額外空間、O(n log n / log log n) 元素移動和 n log 2 n + O(n log log n) 比較對 n 個元素的數組進行排序。 這是第一個在最壞情況下需要 o(n log n) 次移動同時保證 O(n log n) 比較的就地排序算法,但由於涉及的常數因素,該算法主要具有理論意義。
我認為這也是相關的。 我有一份它的打印件,是同事傳給我的,但我沒有讀過。 它似乎涵蓋了基礎理論,但我對這個主題不夠熟悉,無法全面判斷:
http://comjnl.oxfordjournals.org/cgi/content/abstract/38/8/681
最優穩定合並
安東尼奧·西姆沃尼斯
本文展示了如何穩定合並兩個大小分別為 m 和 n,m ≤ n 的序列 A 和 B,使用 O(m+n) 次賦值,O(mlog(n/m+1)) 次比較並僅使用一個常量額外的空間量。 這個結果匹配所有已知的下限...
關鍵的一步是讓合並本身就位。 這並不像那些資料來源所說的那么困難,但是當你嘗試時,你會失去一些東西。
查看合並的一個步驟:
[...列表排序...| x ...列表- A ...| y ...列表- B ...]
我們知道排序后的序列小於其他所有內容, x小於A 中的其他所有內容,而y小於B 中的其他所有內容。 在x小於或等於y的情況下,您只需將指針移動到A的開頭。 在y小於x的情況下,您必須將y改組經過整個A到sorted 。 最后一步是使這變得昂貴的原因(退化情況除外)。
它通常更便宜(特別是當數組實際上每個元素只包含單個單詞時,例如,指向字符串或結構的指針)以權衡一些空間和時間並擁有一個單獨的臨時數組,您可以在它們之間來回排序。
我知道這個問題不太具體。
我想要的是有人告訴我如何將普通的合並排序轉換為就地合並排序(或具有恆定額外空間開銷的合並排序)。
我只能在網上找到說“它太復雜”或“超出本文范圍”的頁面。
唯一已知的就地合並(沒有任何額外空間)的方法太復雜,無法簡化為實際程序。 ( 從這里拍攝)
即使太復雜,如何進行合並排序的基本概念是什么?
#define SWAP(type, a, b) \
do { type t=(a);(a)=(b);(b)=t; } while (0)
static void reverse_(int* a, int* b)
{
for ( --b; a < b; a++, b-- )
SWAP(int, *a, *b);
}
static int* rotate_(int* a, int* b, int* c)
/* swap the sequence [a,b) with [b,c). */
{
if (a != b && b != c)
{
reverse_(a, b);
reverse_(b, c);
reverse_(a, c);
}
return a + (c - b);
}
static int* lower_bound_(int* a, int* b, const int key)
/* find first element not less than @p key in sorted sequence or end of
* sequence (@p b) if not found. */
{
int i;
for ( i = b-a; i != 0; i /= 2 )
{
int* mid = a + i/2;
if (*mid < key)
a = mid + 1, i--;
}
return a;
}
static int* upper_bound_(int* a, int* b, const int key)
/* find first element greater than @p key in sorted sequence or end of
* sequence (@p b) if not found. */
{
int i;
for ( i = b-a; i != 0; i /= 2 )
{
int* mid = a + i/2;
if (*mid <= key)
a = mid + 1, i--;
}
return a;
}
static void ip_merge_(int* a, int* b, int* c)
/* inplace merge. */
{
int n1 = b - a;
int n2 = c - b;
if (n1 == 0 || n2 == 0)
return;
if (n1 == 1 && n2 == 1)
{
if (*b < *a)
SWAP(int, *a, *b);
}
else
{
int* p, * q;
if (n1 <= n2)
p = upper_bound_(a, b, *(q = b+n2/2));
else
q = lower_bound_(b, c, *(p = a+n1/2));
b = rotate_(p, b, q);
ip_merge_(a, p, b);
ip_merge_(b, q, c);
}
}
void mergesort(int* v, int n)
{
if (n > 1)
{
int h = n/2;
mergesort(v, h); mergesort(v+h, n-h);
ip_merge_(v, v+h, v+n);
}
}
添加支持代碼和修改以在任何大小的輔助緩沖區可用時加速合並(在沒有額外內存的情況下仍然有效)。 使用向前和向后合並、環旋轉、小序列合並和排序以及迭代歸並排序。
#include <stdlib.h>
#include <string.h>
static int* copy_(const int* a, const int* b, int* out)
{
int count = b - a;
if (a != out)
memcpy(out, a, count*sizeof(int));
return out + count;
}
static int* copy_backward_(const int* a, const int* b, int* out)
{
int count = b - a;
if (b != out)
memmove(out - count, a, count*sizeof(int));
return out - count;
}
static int* merge_(const int* a1, const int* b1, const int* a2,
const int* b2, int* out)
{
while ( a1 != b1 && a2 != b2 )
*out++ = (*a1 <= *a2) ? *a1++ : *a2++;
return copy_(a2, b2, copy_(a1, b1, out));
}
static int* merge_backward_(const int* a1, const int* b1,
const int* a2, const int* b2, int* out)
{
while ( a1 != b1 && a2 != b2 )
*--out = (*(b1-1) > *(b2-1)) ? *--b1 : *--b2;
return copy_backward_(a1, b1, copy_backward_(a2, b2, out));
}
static unsigned int gcd_(unsigned int m, unsigned int n)
{
while ( n != 0 )
{
unsigned int t = m % n;
m = n;
n = t;
}
return m;
}
static void rotate_inner_(const int length, const int stride,
int* first, int* last)
{
int* p, * next = first, x = *first;
while ( 1 )
{
p = next;
if ((next += stride) >= last)
next -= length;
if (next == first)
break;
*p = *next;
}
*p = x;
}
static int* rotate_(int* a, int* b, int* c)
/* swap the sequence [a,b) with [b,c). */
{
if (a != b && b != c)
{
int n1 = c - a;
int n2 = b - a;
int* i = a;
int* j = a + gcd_(n1, n2);
for ( ; i != j; i++ )
rotate_inner_(n1, n2, i, c);
}
return a + (c - b);
}
static void ip_merge_small_(int* a, int* b, int* c)
/* inplace merge.
* @note faster for small sequences. */
{
while ( a != b && b != c )
if (*a <= *b)
a++;
else
{
int* p = b+1;
while ( p != c && *p < *a )
p++;
rotate_(a, b, p);
b = p;
}
}
static void ip_merge_(int* a, int* b, int* c, int* t, const int ts)
/* inplace merge.
* @note works with or without additional memory. */
{
int n1 = b - a;
int n2 = c - b;
if (n1 <= n2 && n1 <= ts)
{
merge_(t, copy_(a, b, t), b, c, a);
}
else if (n2 <= ts)
{
merge_backward_(a, b, t, copy_(b, c, t), c);
}
/* merge without buffer. */
else if (n1 + n2 < 48)
{
ip_merge_small_(a, b, c);
}
else
{
int* p, * q;
if (n1 <= n2)
p = upper_bound_(a, b, *(q = b+n2/2));
else
q = lower_bound_(b, c, *(p = a+n1/2));
b = rotate_(p, b, q);
ip_merge_(a, p, b, t, ts);
ip_merge_(b, q, c, t, ts);
}
}
static void ip_merge_chunk_(const int cs, int* a, int* b, int* t,
const int ts)
{
int* p = a + cs*2;
for ( ; p <= b; a = p, p += cs*2 )
ip_merge_(a, a+cs, p, t, ts);
if (a+cs < b)
ip_merge_(a, a+cs, b, t, ts);
}
static void smallsort_(int* a, int* b)
/* insertion sort.
* @note any stable sort with low setup cost will do. */
{
int* p, * q;
for ( p = a+1; p < b; p++ )
{
int x = *p;
for ( q = p; a < q && x < *(q-1); q-- )
*q = *(q-1);
*q = x;
}
}
static void smallsort_chunk_(const int cs, int* a, int* b)
{
int* p = a + cs;
for ( ; p <= b; a = p, p += cs )
smallsort_(a, p);
smallsort_(a, b);
}
static void mergesort_lower_(int* v, int n, int* t, const int ts)
{
int cs = 16;
smallsort_chunk_(cs, v, v+n);
for ( ; cs < n; cs *= 2 )
ip_merge_chunk_(cs, v, v+n, t, ts);
}
static void* get_buffer_(int size, int* final)
{
void* p = NULL;
while ( size != 0 && (p = malloc(size)) == NULL )
size /= 2;
*final = size;
return p;
}
void mergesort(int* v, int n)
{
/* @note buffer size may be in the range [0,(n+1)/2]. */
int request = (n+1)/2 * sizeof(int);
int actual;
int* t = (int*) get_buffer_(request, &actual);
/* @note allocation failure okay. */
int tsize = actual / sizeof(int);
mergesort_lower_(v, n, t, tsize);
free(t);
}
這個答案有一個代碼示例,它實現了 Bing-Chao Huang 和 Michael A. Langston 的論文Practical In-Place Merging 中描述的算法。 我不得不承認我不了解細節,但合並步驟的給定復雜度是 O(n)。
從實踐的角度來看,有證據表明純就地實現在現實世界場景中的表現並不好。 例如,C++ 標准定義了std::inplace_merge ,顧名思義就是就地合並操作。
假設 C++ 庫通常被很好地優化,看看它是如何實現的很有趣:
實現委托給__inplace_merge ,它通過嘗試分配臨時緩沖區來避免問題:
typedef _Temporary_buffer<_BidirectionalIterator, _ValueType> _TmpBuf;
_TmpBuf __buf(__first, __len1 + __len2);
if (__buf.begin() == 0)
std::__merge_without_buffer
(__first, __middle, __last, __len1, __len2, __comp);
else
std::__merge_adaptive
(__first, __middle, __last, __len1, __len2, __buf.begin(),
_DistanceType(__buf.size()), __comp);
否則,它會回退到一個實現( __merge_without_buffer ),它不需要額外的內存,但不再在 O(n) 時間內運行。
看起來很像。 它委托給一個函數,該函數也嘗試分配一個緩沖區。 根據它是否有足夠的元素,它會選擇實現。 常量內存回退函數稱為__buffered_inplace_merge 。
也許即使回退仍然是 O(n) 時間,但關鍵是如果臨時內存可用,他們不使用實現。
請注意,C++ 標准通過將所需的復雜度從 O(n) 降低到 O(N log N) 來明確賦予實現選擇這種方法的自由:
復雜性:如果有足夠的額外內存可用,正好是 N-1 次比較。 如果內存不足,O(N log N) 次比較。
當然,這不能作為證明永遠不應該使用 O(n) 時間內的常量空間就地合並。 另一方面,如果它會更快,優化的 C++ 庫可能會切換到這種類型的實現。
這是我的 C 版本:
void mergesort(int *a, int len) {
int temp, listsize, xsize;
for (listsize = 1; listsize <= len; listsize*=2) {
for (int i = 0, j = listsize; (j+listsize) <= len; i += (listsize*2), j += (listsize*2)) {
merge(& a[i], listsize, listsize);
}
}
listsize /= 2;
xsize = len % listsize;
if (xsize > 1)
mergesort(& a[len-xsize], xsize);
merge(a, listsize, xsize);
}
void merge(int *a, int sizei, int sizej) {
int temp;
int ii = 0;
int ji = sizei;
int flength = sizei+sizej;
for (int f = 0; f < (flength-1); f++) {
if (sizei == 0 || sizej == 0)
break;
if (a[ii] < a[ji]) {
ii++;
sizei--;
}
else {
temp = a[ji];
for (int z = (ji-1); z >= ii; z--)
a[z+1] = a[z];
ii++;
a[f] = temp;
ji++;
sizej--;
}
}
}
我知道這個問題不太具體。
我想要的是有人告訴我如何將普通的合並排序轉換為就地合並排序(或具有恆定額外空間開銷的合並排序)。
我只能在網上找到說“它太復雜”或“超出本文范圍”的頁面。
唯一已知的就地合並(沒有任何額外空間)的方法太復雜,無法簡化為實際程序。 ( 從這里拍攝)
即使太復雜,如何進行合並排序的基本概念是什么?
我知道我遲到了,但這是我昨天寫的一個解決方案。 我也在別處發布了這個,但這似乎是 SO 上最受歡迎的就地合並線程。 我也沒有在其他任何地方看到過這個算法,所以希望這可以幫助一些人。
該算法采用最簡單的形式,以便於理解。 可以顯着調整它以獲得額外的速度。 平均時間復雜度為:O(n.log₂n) 用於穩定的就地數組合並,O(n.(log₂n)²) 用於整體排序。
// Stable Merge In Place Sort
//
//
// The following code is written to illustrate the base algorithm. A good
// number of optimizations can be applied to boost its overall speed
// For all its simplicity, it does still perform somewhat decently.
// Average case time complexity appears to be: O(n.(log₂n)²)
#include <stddef.h>
#include <stdio.h>
#define swap(x, y) (t=(x), (x)=(y), (y)=t)
// Both sorted sub-arrays must be adjacent in 'a'
// Assumes that both 'an' and 'bn' are always non-zero
// 'an' is the length of the first sorted section in 'a', referred to as A
// 'bn' is the length of the second sorted section in 'a', referred to as B
static void
merge_inplace(int A[], size_t an, size_t bn)
{
int t, *B = &A[an];
size_t pa, pb; // Swap partition pointers within A and B
// Find the portion to swap. We're looking for how much from the
// start of B can swap with the end of A, such that every element
// in A is less than or equal to any element in B. This is quite
// simple when both sub-arrays come at us pre-sorted
for(pa = an, pb = 0; pa>0 && pb<bn && B[pb] < A[pa-1]; pa--, pb++);
// Now swap last part of A with first part of B according to the
// indicies we found
for (size_t index=pa; index < an; index++)
swap(A[index], B[index-pa]);
// Now merge the two sub-array pairings. We need to check that either array
// didn't wholly swap out the other and cause the remaining portion to be zero
if (pa>0 && (an-pa)>0)
merge_inplace(A, pa, an-pa);
if (pb>0 && (bn-pb)>0)
merge_inplace(B, pb, bn-pb);
} // merge_inplace
// Implements a recursive merge-sort algorithm with an optional
// insertion sort for when the splits get too small. 'n' must
// ALWAYS be 2 or more. It enforces this when calling itself
static void
merge_sort(int a[], size_t n)
{
size_t m = n/2;
// Sort first and second halves only if the target 'n' will be > 1
if (m > 1)
merge_sort(a, m);
if ((n-m)>1)
merge_sort(a+m, n-m);
// Now merge the two sorted sub-arrays together. We know that since
// n > 1, then both m and n-m MUST be non-zero, and so we will never
// violate the condition of not passing in zero length sub-arrays
merge_inplace(a, m, n-m);
} // merge_sort
// Print an array */
static void
print_array(int a[], size_t size)
{
if (size > 0) {
printf("%d", a[0]);
for (size_t i = 1; i < size; i++)
printf(" %d", a[i]);
}
printf("\n");
} // print_array
// Test driver
int
main()
{
int a[] = { 17, 3, 16, 5, 14, 8, 10, 7, 15, 1, 13, 4, 9, 12, 11, 6, 2 };
size_t n = sizeof(a) / sizeof(a[0]);
merge_sort(a, n);
print_array(a, n);
return 0;
} // main
利用 C++ std::inplace_merge,就地歸並排序可以實現如下:
template< class _Type >
inline void inplace_merge_sort_hybrid(_Type* src, int l, int r, int threshold = 1024)
{
if (r == l) {
return;
}
if ((r - l) <= threshold) {
std::sort(src + l, src + r + 1); // could be insertion sort, with a smaller threshold
return;
}
int m = ((r + l) / 2);
inplace_merge_sort_hybrid(src, l, m, threshold);
inplace_merge_sort_hybrid(src, m + 1, r, threshold);
std::inplace_merge(src + l, src + m + 1, src + r + 1);
}
我剛剛嘗試使用插入排序算法,使用以下步驟在JAVA 中進行合並排序的就地合並算法。
1) 有兩個排序數組可用。
2) 比較每個數組的第一個值; 並將最小值放入第一個數組。
3)使用插入排序(從左到右遍歷)將較大的值放入第二個數組中。
4)然后再次比較第一個數組的第二個值和第二個數組的第一個值,並執行相同的操作。 但是當交換發生時,有一些線索可以跳過比較進一步的項目,但只需要交換。
我這里做了一些優化; 在插入排序中保持較少的比較。
我發現此解決方案的唯一缺點是它需要在第二個數組中對數組元素進行更大的交換。
例如)
第一個___數組:3, 7, 8, 9
第二個數組:1、2、4、5
然后 7, 8, 9 使第二個數組每次將其所有元素交換(向左移動一個)一個,以將自己放在最后一個。
所以這里的假設是交換項目與比較兩個項目相比可以忽略不計。
https://github.com/skanagavelu/algorithams/blob/master/src/sorting/MergeSort.java
package sorting;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] array = { 5, 6, 10, 3, 9, 2, 12, 1, 8, 7 };
mergeSort(array, 0, array.length -1);
System.out.println(Arrays.toString(array));
int[] array1 = {4, 7, 2};
System.out.println(Arrays.toString(array1));
mergeSort(array1, 0, array1.length -1);
System.out.println(Arrays.toString(array1));
System.out.println("\n\n");
int[] array2 = {4, 7, 9};
System.out.println(Arrays.toString(array2));
mergeSort(array2, 0, array2.length -1);
System.out.println(Arrays.toString(array2));
System.out.println("\n\n");
int[] array3 = {4, 7, 5};
System.out.println(Arrays.toString(array3));
mergeSort(array3, 0, array3.length -1);
System.out.println(Arrays.toString(array3));
System.out.println("\n\n");
int[] array4 = {7, 4, 2};
System.out.println(Arrays.toString(array4));
mergeSort(array4, 0, array4.length -1);
System.out.println(Arrays.toString(array4));
System.out.println("\n\n");
int[] array5 = {7, 4, 9};
System.out.println(Arrays.toString(array5));
mergeSort(array5, 0, array5.length -1);
System.out.println(Arrays.toString(array5));
System.out.println("\n\n");
int[] array6 = {7, 4, 5};
System.out.println(Arrays.toString(array6));
mergeSort(array6, 0, array6.length -1);
System.out.println(Arrays.toString(array6));
System.out.println("\n\n");
//Handling array of size two
int[] array7 = {7, 4};
System.out.println(Arrays.toString(array7));
mergeSort(array7, 0, array7.length -1);
System.out.println(Arrays.toString(array7));
System.out.println("\n\n");
int input1[] = {1};
int input2[] = {4,2};
int input3[] = {6,2,9};
int input4[] = {6,-1,10,4,11,14,19,12,18};
System.out.println(Arrays.toString(input1));
mergeSort(input1, 0, input1.length-1);
System.out.println(Arrays.toString(input1));
System.out.println("\n\n");
System.out.println(Arrays.toString(input2));
mergeSort(input2, 0, input2.length-1);
System.out.println(Arrays.toString(input2));
System.out.println("\n\n");
System.out.println(Arrays.toString(input3));
mergeSort(input3, 0, input3.length-1);
System.out.println(Arrays.toString(input3));
System.out.println("\n\n");
System.out.println(Arrays.toString(input4));
mergeSort(input4, 0, input4.length-1);
System.out.println(Arrays.toString(input4));
System.out.println("\n\n");
}
private static void mergeSort(int[] array, int p, int r) {
//Both below mid finding is fine.
int mid = (r - p)/2 + p;
int mid1 = (r + p)/2;
if(mid != mid1) {
System.out.println(" Mid is mismatching:" + mid + "/" + mid1+ " for p:"+p+" r:"+r);
}
if(p < r) {
mergeSort(array, p, mid);
mergeSort(array, mid+1, r);
// merge(array, p, mid, r);
inPlaceMerge(array, p, mid, r);
}
}
//Regular merge
private static void merge(int[] array, int p, int mid, int r) {
int lengthOfLeftArray = mid - p + 1; // This is important to add +1.
int lengthOfRightArray = r - mid;
int[] left = new int[lengthOfLeftArray];
int[] right = new int[lengthOfRightArray];
for(int i = p, j = 0; i <= mid; ){
left[j++] = array[i++];
}
for(int i = mid + 1, j = 0; i <= r; ){
right[j++] = array[i++];
}
int i = 0, j = 0;
for(; i < left.length && j < right.length; ) {
if(left[i] < right[j]){
array[p++] = left[i++];
} else {
array[p++] = right[j++];
}
}
while(j < right.length){
array[p++] = right[j++];
}
while(i < left.length){
array[p++] = left[i++];
}
}
//InPlaceMerge no extra array
private static void inPlaceMerge(int[] array, int p, int mid, int r) {
int secondArrayStart = mid+1;
int prevPlaced = mid+1;
int q = mid+1;
while(p < mid+1 && q <= r){
boolean swapped = false;
if(array[p] > array[q]) {
swap(array, p, q);
swapped = true;
}
if(q != secondArrayStart && array[p] > array[secondArrayStart]) {
swap(array, p, secondArrayStart);
swapped = true;
}
//Check swapped value is in right place of second sorted array
if(swapped && secondArrayStart+1 <= r && array[secondArrayStart+1] < array[secondArrayStart]) {
prevPlaced = placeInOrder(array, secondArrayStart, prevPlaced);
}
p++;
if(q < r) { //q+1 <= r) {
q++;
}
}
}
private static int placeInOrder(int[] array, int secondArrayStart, int prevPlaced) {
int i = secondArrayStart;
for(; i < array.length; i++) {
//Simply swap till the prevPlaced position
if(secondArrayStart < prevPlaced) {
swap(array, secondArrayStart, secondArrayStart+1);
secondArrayStart++;
continue;
}
if(array[i] < array[secondArrayStart]) {
swap(array, i, secondArrayStart);
secondArrayStart++;
} else if(i != secondArrayStart && array[i] > array[secondArrayStart]){
break;
}
}
return secondArrayStart;
}
private static void swap(int[] array, int m, int n){
int temp = array[m];
array[m] = array[n];
array[n] = temp;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.