Performance Haskell/GHC使用“过滤器”/“列表理解”对原始排序的性能
使用Performance Haskell/GHC使用“过滤器”/“列表理解”对原始排序的性能,performance,sorting,haskell,functional-programming,list-comprehension,Performance,Sorting,Haskell,Functional Programming,List Comprehension,使用-O3编译,使用 quicksort [] = [] quicksort (x : xs) = quicksort (filter (< x) xs) ++ [x] ++ quicksort (filter (>= x) xs) quicksort2 [] = [] quicksort2 (x : xs) = quicksort2 [y | y <- xs, y &
-O3
编译,使用
quicksort [] = []
quicksort (x : xs) = quicksort (filter (< x) xs)
++ [x] ++
quicksort (filter (>= x) xs)
quicksort2 [] = []
quicksort2 (x : xs) = quicksort2 [y | y <- xs, y < x]
++ [x] ++
quicksort2 [y | y <- xs, y >= x]
minisort [] = []
minisort xs = let x = minimum xs
in x : minisort (delete x xs)
这些不是Haskell本机合并排序
,也不应该是
我注意到迷你排序
始终比快速排序
运行得快得多,考虑到所涉及操作的复杂性,这似乎是可以理解的。我不明白的是,quicksort2有一个一致的轻微边缘quicksort2
超过了quicksort2
。列表理解通常比过滤表达式更有效吗
到目前为止,我使用的是,与nf,
ghci
的:set+s
,以及2个远程performance displayant在线编译器(,)
标准基准排序最坏情况[50004999..1]:[Int]
:
benchmarking quicksort
time 2.283 s (2.191 s .. 2.450 s)
0.999 R² (0.998 R² .. 1.000 R²)
mean 2.434 s (2.368 s .. 2.485 s)
std dev 79.23 ms (0.0 s .. 88.75 ms)
variance introduced by outliers: 19% (moderately inflated)
benchmarking quicksort2
time 2.203 s (1.982 s .. 2.455 s)
0.998 R² (0.994 R² .. 1.000 R²)
mean 2.327 s (2.275 s .. 2.359 s)
std dev 49.11 ms (0.0 s .. 56.47 ms)
variance introduced by outliers: 19% (moderately inflated)
benchmarking minisort
time 257.2 ms (229.7 ms .. 276.4 ms)
0.997 R² (NaN R² .. 1.000 R²)
mean 274.4 ms (264.3 ms .. 280.9 ms)
std dev 9.714 ms (2.538 ms .. 12.94 ms)
variance introduced by outliers: 16% (moderately inflated)
quicksort2
always(不同的测试用例、顺序和上下文)的性能比quicksort
好一点minisort
,到目前为止,它的性能比这两者都好。这是什么版本的GHC?您是如何测量速度的,基于什么输入?我非常惊讶,因为filter
是使用build/foldr
表单实现的,该表单应该类似于列表理解。如果您在GHCi中尝试一些东西,它们没有得到优化。还要注意,没有-O3
;只需-O2
。这种情况最终可能会改变,但从一开始就一直如此。在任何非微小列表上,minisort
()都不会更快,因为这是O(n²)最佳情况,而任何像样的排序算法的平均情况复杂度都是O(n·logn)。你是怎么测量的?特别是,您采取了哪些措施来确保实际评估结果?我怀疑你只是列出了排序后的列表——这还不够。请发布你的基准代码和你用来运行它的过程。还要注意的是,您的“快速排序”不是随机的,因此它容易受到病理病例的影响,并且它对每个列表执行两次传递(尽管后者在这里可能并不可怕)。您正在测试的降序列表正是dfeuer所指的病理输入类型。你知道为什么吗?所以你比较了几种二次时间算法。关于为什么这里有些人比其他人慢或快,答案不会特别有趣。我读错了。这里没有列表融合的可能性。如果quicksort
和quicksort2
之间的差异是真实的(这几乎不具有统计意义,如果存在一些愚蠢的依赖于先运行哪个基准或其他什么的情况,我也不会感到惊讶),那么这可能是优化中的脆弱之处。选择排序比快速排序更简单,所以当快速排序遇到最坏的情况时,它会更快,我并不感到惊讶。