为什么标准合并排序不到位?

时间:2015-06-14 14:45:46

标签: algorithm sorting

在合并排序的合并算法中,我不明白我们必须使用辅助数组L,R?为什么我们不能保持2个指针对应哪个元素我们在2个子阵列L和R中进行比较,以便合并排序算法保持原位?

感谢。

3 个答案:

答案 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;
}