提问者对基于排序网络的 5 中位数实现特别感兴趣,所以我将讨论这个具体案例。对文献的简要回顾表明,根据各种指标,最佳解决方案是什么样的。
Michael Codish、Luís Cruz-Filipe、Thorsten Ehlers、Mike Müller 和 Peter Schneider-Kamp。“排序网络:到最后再回来。” Journal of Computer and System Sciences (2016) 在表 1 中显示,对于n =5,compare-swap 的最小数量为 9,网络的最小深度为 5。因为每个 compare-swap 相当于两个 min/最大操作,所需的最小/最大操作的最小数量是 18。
Lukáŝ Sekanina,“中值电路的进化设计空间探索”。在:EvoWorkshops,2004 年 3 月,第 240-249 页,给出了表 1 中最优五输入中值选择网络所需的最小/最大操作数为 10。
威廉·加萨奇、韦恩·凯利和威廉·普格。“为小 i, n 找到第 i 个最大的 n。” ACM SIGACT 新闻27,不。2 (1996):88-96,表 1:5 的中位数至少需要 6 次比较。
通常,具有最少操作数的排序网络不会简单地通过消除冗余操作而简化为具有最少操作数的中值选择网络。但是有可能找到至少对于某些n值以最佳方式减少的网络。对于n = 5,对此类网络进行暴力搜索是可行的。
下面的代码显示了包含 9 个比较交换操作或 18 个最小/最大操作的五输入排序网络的四种变体。当使用这些编译时,FULL_SORT = 0
会变成具有 10 分钟/最大操作的中值选择网络。所以根据这个指标,排序和中值选择都是最优的。
但是,当用作排序网络时,所有四个变体的深度都是 6,而不是最小的 5。此外,当配置为基于比较而不是最小/最大操作的中值选择网络时,都需要七次而不是最少的六次比较。
Compiler Explorer (godbolt) 的示例编译结果:使用 18 min/max 操作进行五输入排序,使用 10 分钟/最大操作进行五输入中位数。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define VARIANT 1
#define USE_MIN_MAX 1
#define FULL_SORT 0
typedef float T;
#if USE_MIN_MAX
#define MIN(a,b) ((T)(fmin(a,b)))
#define MAX(a,b) ((T)(fmax(a,b)))
#define SWAP(i,j) do { T s = MIN(a##i,a##j); T t = MAX(a##i,a##j); a##i = s; a##j = t; } while (0)
#else // USE_MIN_MAX
#define MIN(a,b) (((a) > (b)) ? (b) : (a))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define SWAP(i,j) do { if (a##i > a##j) { T temp = a##i; a##i = a##j; a##j = temp; }} while (0)
#endif // USE_MIN_MAX
/* Use sorting/median network to fully or partially sort array of five values
and return the median value
*/
T network5 (T *a)
{
// copy to scalars
T a0, a1, a2, a3, a4;
a0=a[0];a1=a[1];a2=a[2];a3=a[3];a4=a[4];
#if VARIANT == 1
SWAP (0, 1); SWAP (2, 3);
SWAP (0, 2); SWAP (1, 3);
SWAP (2, 1);
SWAP (1, 4);
SWAP (1, 2);
SWAP (0, 1); SWAP (3, 4);
#elif VARIANT == 2
SWAP (3, 4); SWAP (0, 2);
SWAP (2, 4); SWAP (0, 3);
SWAP (2, 3);
SWAP (1, 2);
SWAP (0, 1); SWAP (2, 3);
SWAP (3, 4);
#elif VARIANT == 3
SWAP (3, 2); SWAP (0, 4);
SWAP (2, 4); SWAP (0, 3);
SWAP (2, 3);
SWAP (1, 2);
SWAP (0, 1); SWAP (2, 3);
SWAP (3, 4);
#elif VARIANT == 4
SWAP (2, 4); SWAP (0, 1);
SWAP (0, 2); SWAP (1, 4);
SWAP (2, 3);
SWAP (1, 2);
SWAP (2, 3); SWAP (0, 1);
SWAP (3, 4);
#else
#error unsupported VARIANT
#endif
#if FULL_SORT
// copy back sorted results
a[0]=a0;a[1]=a1;a[2]=a2;a[3]=a3;a[4]=a4;
#endif
// return median-of-5
return a2;
}