我想知道如何编写快速排序的高效版本,其中列表在一次传递中被分区。
我有这段代码,
let rec quicksort' = function
[] -> []
| x::xs -> let small = List.filter (fun y -> y < x ) xs
and large = List.filter (fun y -> y > x ) xs
in quicksort' small @ (x :: quicksort' large);;
但是在这里,我要经历超过1次的清单(对于小型和大型呼叫2次快速排序)。
这个想法是在只需一步的情况下完成,而不会超过1次。
答案 0 :(得分:18)
List.partition是要走的路:
let rec quicksort = function
| [] -> []
| x::xs -> let smaller, larger = List.partition (fun y -> y < x) xs
in quicksort smaller @ (x::quicksort larger)
请注意,List.partition
有助于避免通过xs
进行一次冗余遍历。你仍然需要递归地对较小的部分和较大的部分进行排序,因为这是Quicksort的工作方式。
我不得不说这个版本的quicksort
远没有效率。 Quicksort algorithm是一种固有的就地算法,它递归地改变输入数组。另一个因素是枢轴选择;选择第一个元素作为支点并不总是一个好主意。
这些因素导致效率的实现极为不同(可能使用Array
和变异)。 List
上的Quicksort应该用于演示算法的概念及其递归的美感。
答案 1 :(得分:4)
如果您需要编写有效的排序功能,您可能需要阅读这篇富有洞察力的论文:Engineering a sort function。否则,我很确定List.sort也写得很好。