最快的无条件排序算法

时间:2013-10-23 09:00:18

标签: algorithm sorting

我有一个函数,可以使用两个元素并按升序返回:

void Sort2(int &a, int &b) { 
  if (a < b) return; 
  int t = a; 
  a = b; 
  b = t; 
}

如果不允许使用额外的条件运算符,使用此函数对具有N个条目的数组进行排序的最快方法是什么? 这意味着我的整个程序应该是这样的:

int main(){
  int a[N];
     // fill a array

  const int NS = ...; // number of comparison, depending on N.
  const int c[NS] = { {0,1}, {0,2}, ... }; // consequence of indices pairs generated depending on N.
  for( int i = 0; i < NS; i++ ) {
    Sort2(a[c[i][0]], a[c[i][1]]);
  }
     // sort is finished
  return 1;
}

大多数快速排序算法都使用条件来决定做什么。当然有bubble sort,但需要M = N(N-1)/ 2比较。这不是最优的,例如,N = 4需要M = 6比较,同时4个条目可以用5分类:

Sort2(a[0],a[1]);
Sort2(a[2],a[3]);
Sort2(a[1],a[3]);
Sort2(a[0],a[2]);
Sort2(a[1],a[2]);

2 个答案:

答案 0 :(得分:6)

标准方法称为Bitonic Mergesort。在并列化时,它是高效的,并且在未并行化时仅比传统算法效率稍低。 Bitonic mergesort是一种特殊类型的更广泛的算法,称为“排序网络”;在排序网络中,它的一些重新排序是按照所需排序的 reverse 顺序排列是不常见的(尽管算法完成后一切都按正确的顺序排列)。您可以使用Sort2为第一个参数传递比第二个参数更高的数组插槽。

答案 1 :(得分:0)

对于N 2的幂,你可以通过使用“merge-sortish”方法来概括你使用的方法:你分别对前半部分和后半部分进行排序,然后使用很少比较。

例如,考虑一个大小为8的数组。并假设前半部分已排序,后半部分已排序(通过递归应用相同的方法):

A B C D P Q R S

在第一轮中,你比较1对1,2对2等:

---------
|       |
| ---------
| |     | |
A B C D P Q R S
    | |     | |
    | ---------
    |       |
    ---------

在这一轮之后,第一个和最后一个元素在正确的位置,所以你需要重复内部6个元素的过程(我保持元素的名称相同,因为它们最终在哪里是未知的):

  -------
  |     |
  | -------
  | |   | |
A B C D P Q R S
      |     |
      -------

在下一轮中,比较内部4个元素,并在最后一轮中比较内部2。

f(n)为对长度为n的数组进行排序所需的比较次数(其中n目前的幂为2)。显然,已经对包含1个元素的数组进行了排序:

f(1) = 0

对于较长的数组,首先需要对两半进行排序,然后执行上述步骤。对于n=8,进行了4+3+2+1 = (n/2)(n/2+1)/2次比较。因此一般来说:

f(n) = 2 f(n/2) + (n/2)(n/2+1)/2

请注意,对于n=4,这确实给出了:

f(4) = 2 f(2) + 2*3/2
     = 2 * (2 f(1) + 1*2/2) + 3
     = 5

为了方便{2}没有2的幂,重要的是在奇数长度数组上进行合并步骤。最简单的策略似乎是比较两个子阵列的最小元素(产生最小元素),然后继续在数组的其余部分(现在甚至是长度)。

如果我们写n,我们现在可以用简短的方式编写递归公式(我使用g(k) = k(k+1)/22k来区分偶数和奇数):

2k+1

关于如何处理这个问题的一些伪代码:

f(1) = 0
f(2k) = 2 f(k) + g(k)
f(2k+1) = f(k+1) + f(k) + 1 + g(k)

你可以通过

在你的阵列上运行它
function sort(A, start, length) {
    if (length == 1) {
        // do nothing
    } else if (length is even) {
        sort(A, start, length/2)
        sort(A, start+length/2, length/2)
        merge(A, start, length)
    } else if (length is odd) {
        sort(A, start, length/2+1)
        sort(A, start+length/2+1, length/2)
        Sort2(A[start], A[start+length/2+1])
        merge(A, start+1, length-1)            
    }
}

function merge(A, start, length) {
    if (length > 0) {
        for (i = 0; i < length/2; i++)
            Sort2(A[i], A[i]+length/2)
        merge(A, start+1, length-2)
    }
}