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数组排序
对于如此小的数据集,您需要尽可能简单的算法。更可能的是,一个基本的插入排序可以达到您想要的效果。
需要了解更多关于运行的系统的信息,每秒需要做多少次这样的工作,等等…但一般的小规则是保持简单。流沙之类的是没有好处的。