关于性能:快速算法实现,以排序非常小的列表

Fast algorithm implementation to sort very small list

这是我很久以前遇到的问题。我想我可以征求你的意见。假设我有非常小的数字列表(整数),4或8个元素,需要快速排序。最好的方法/算法是什么?

我的方法是使用max/min函数(10个函数来排序4个数字,没有分支,IIRC)。

1
2
3
4
5
6
// s(i,j) == max(i,j), min(i,j)
i,j = s(i,j)
k,l = s(k,l)
i,k = s(i,k) // i on top
j,l = s(j,l) // l on bottom
j,k = s(j,k)

我想我的问题更多地与实现有关,而不是算法的类型。

此时,它变得有点依赖于硬件,所以让我们假设使用带有SSE3的Intel64位处理器。

谢谢


对于这样的小数组,您可能应该研究排序网络。正如您在该页上看到的,插入排序可以表示为排序网络。但是,如果事先知道阵列的大小,就可以设计出一个最佳网络。看看这个站点,它可以帮助您为给定大小的数组找到最佳的排序网络(尽管我相信最优的大小只有16个)。比较器甚至可以在并行操作中分组在一起。比较器基本上与S(x,y)函数相同,但是如果你真的希望它很快,你不应该使用最小值和最大值,因为这样你做了两倍的比较。

如果您需要这种排序算法来处理大范围的大小,那么您可能只需要按照其他人的建议进行插入排序。


为了对少量数字进行排序,您需要一个简单的算法,因为复杂性会增加更多的开销。

最有效的排序方法是将排序算法分解为线性比较,从而消除所有开销:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function sort(i,j,k,l) {
  if (i < j) {
    if (j < k) {
      if (k < l) return [i,j,k,l];
      if (j < l) return [i,j,l,k];
      if (i < l) return [i,l,j,k];
      return [l,i,j,k];
    } else if (i < k) {
      if (j < l) return [i,k,j,l];
      if (k < l) return [i,k,l,j];
      if (i < l) return [i,l,k,j];
      return [l,i,k,j];
    } else {
      if (j < l) return [k,i,j,l];
      if (i < l) return [k,i,l,j];
      if (k < l) return [k,l,i,j];
      return [l,k,i,j];
    }
  } else {
    if (i < k) {
      if (k < l) return [j,i,k,l];
      if (i < l) return [j,i,l,k];
      if (j < l) return [j,l,i,k];
      return [l,j,i,k];
    } else if (j < k) {
      if (i < l) return [j,k,i,l];
      if (k < l) return [j,k,l,i];
      if (j < l) return [j,l,k,i];
      return [l,j,k,i];
    } else {
      if (i < l) return [k,j,i,l];
      if (j < l) return [k,j,l,i];
      if (k < l) return [k,l,j,i];
      return [l,k,j,i];
    }
  }
}

但是,对于您添加的每个额外项目,代码都会增长很多。添加第五项使代码大约大四倍。在8个项目中,它大约有30000行,所以尽管它仍然是最有效的,但它有很多代码,您必须编写一个程序来编写代码以使其正确。


我看到您已经有了一个使用5个比较的解决方案(假设s(i,j)将两个数字比较一次,然后交换它们或不交换)。如果您坚持基于比较的排序,那么您不能用少于5个比较来进行排序。

这可以证明,因为有4个!=24种订购4个号码的可能方法。每个比较只能将可能性减半,因此通过4个比较,您只能区分2^4=16个可能的订单。


插入排序被认为最适合小数组。请参见小数组的快速稳定排序(在32或64个元素下)


分类网络可以很容易地在SIMD中实现,尽管它在n=16时开始变得丑陋。对于n=4或n=8,尽管这是一个很好的选择。理想情况下,您需要大量的小数据集来同时进行排序,例如,如果您要对8位值进行排序,那么您需要至少16个数据集进行排序—跨SIMD向量进行这种排序要困难得多。

另请参见:最快的固定长度6 int数组排序


对于如此小的数据集,您需要尽可能简单的算法。更可能的是,一个基本的插入排序可以达到您想要的效果。

需要了解更多关于运行的系统的信息,每秒需要做多少次这样的工作,等等…但一般的小规则是保持简单。流沙之类的是没有好处的。