在合并排序的合并算法中,我不明白我们必须使用辅助数组L,R?为什么我们不能保持2个指针对应哪个元素我们在2个子阵列L和R中进行比较,以便合并排序算法保持原位?
感谢。
答案 0 :(得分:3)
说你分裂你的数组s.th. L使用原始数组的前半部分,R使用后半部分。
然后说durign合并R中的前几个元素小于L中的最小元素。如果要将它们放在合并结果的正确位置,则必须覆盖L中尚未处理的元素在合并步骤期间。
当然,你可以做出不同的分裂。但是你总是可以构建这样一个(然后略有不同)的例子。
答案 1 :(得分:1)
我在这里的第一篇文章。温柔点!
这是我的一个简单易懂的稳定就地归并排序的解决方案。我昨天写了这个。我不确定以前没有做过,但我没见过,所以也许吧?
以下就地合并算法的一个缺点在某些条件下可能退化为 O(n²),但在实践中通常为 O(n.log₂n)。这种退化可以通过某些更改来缓解,但我希望在代码示例中保持基本算法的纯正,以便易于理解。
再加上驱动 merge_sort() 函数的 O(log₂n) 时间复杂度,这向我们展示了一个典型的 O(n.(log₂n)²) 总体时间复杂度,最坏的情况是 O(n².log₂n),这不是很好,但再次通过一些调整,它可以使它几乎总是在 O(n.(log₂n)²) 时间内运行,并且凭借其良好的 CPU 缓存局部性,即使对于高达 1M 的 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
答案 2 :(得分:0)
如果您曾经尝试编写适当的合并排序,那么您很快就会发现为什么无法合并两个子数组-您基本上需要读取和写入数组的相同范围,它将互相覆盖。因此,我们需要任何辅助数组:
vector<int> merge_sort(vector<int>& vs, int l, int r, vector<int>& temp)
{
if(l==r) return vs; // recursion must have an end condition
int m = (l+r)/2;
merge_sort(vs, l, m, temp);
merge_sort(vs, m+1, r, temp);
int il = l, ir=m+1, i=l;
while(il <= m && ir <= r)
{
if(vs[il] <= vs[ir])
temp[i++] = vs[il++];
else
temp[i++] = vs[ir++];
}
// copy left over items(only one of below will apply
while(il <= m) temp[i++] = vs[il++];
while(ir <= r) temp[i++] = vs[ir++];
for(i=l; i<=r; ++i) vs[i] = temp[i];
return vs;
}