この数を計算する関数を書くだけです。それぞれfilter p xs
がlength xs
比較を実行します。それだけです。
現在、コードはパーティションを実行するために 3 つのパスを実行します。1 回のパスで 3 方向のパーティションを実行するように書き直すことができます。パスの数をパラメーターにすることができます。
もう 1 つの問題は、すべての等しい要素を含むことが既にわかっている中間セクションの不必要な並べ替えです。この不必要な並べ替えが実行されるかどうかを知らせるために、これもパラメーターにすることができます。
_NoSort = False
_DoSort = True
qsCount xs n midSortP = qs 0 xs id -- return number of comparisons that
where -- n-pass `qSort xs` would perform
qs !i [] k = k i
qs !i (p:xs) k =
let (a,b,c) = (filter (< p) xs, filter (== p) xs, filter (> p) xs)
in qs (i+n*length xs) a (\i-> g i b (\i-> qs i c k))
g i b k | midSortP = qs i b k
| otherwise = k i
ご覧のとおり、1 回のパスよりも 3 回のパスの方が 3 倍多くの比較が必要であり、中間の並べ替えは、リストに 2 つ以上の等しい要素がある場合にのみ違いを生むことができます。
*Main> qsCount ( concat $ replicate 4 [10,9..1]) 3 _NoSort
630
*Main> qsCount ( concat $ replicate 4 [10,9..1]) 3 _DoSort
720
*Main> qsCount ( concat $ replicate 4 [10,9..1]) 1 _NoSort
210
*Main> qsCount ( concat $ replicate 4 [10,9..1]) 1 _DoSort
240
*Main> qsCount [5,3,8,4,10,1,6,2,7,9] 1 _NoSort
19
*Main> qsCount [5,3,8,4,10,1,6,2,7,9] 1 _DoSort
19
*Main> qsCount (replicate 10 1) 1 _NoSort
9
*Main> qsCount (replicate 10 1) 1 _DoSort
45
*Main> qsCount [15, 11, 9, 25, -3] 3 _DoSort
21