我有一个函数,可以使用两个元素并按升序返回:
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]);
答案 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)/2
和2k
来区分偶数和奇数):
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)
}
}