Skip to main content
4 of 6
edited title
Quaxton Hale
  • 2.6k
  • 1
  • 35
  • 52

Optimizing a divide-and-conquer algorithm for counting inversions

I have the following code:

inversions :: (Ord a) => [a] -> Int
inversions xs = snd $ countInv' (xs, length xs)

countInv' :: (Ord a) => ([a], Int) -> ([a], Int)
countInv' ([], _) = ([], 0)
countInv' ([x], _) = ([x], 0)
countInv' (xs, n) = (sorted, leftInv + splitInv + rightInv)
    where
        leftLen = n `div` 2
        rightLen = n - leftLen
        (left, right) = splitAt leftLen xs
        (sortedLeft, leftInv) = countInv' (left, leftLen)
        (sortedRight, rightInv) = countInv' (right, rightLen)
        (sorted, splitInv) = countSplitInv' (sortedLeft, leftLen) (sortedRight, rightLen)

countSplitInv' :: (Ord a) => ([a], Int) -> ([a], Int) -> ([a], Int)
countSplitInv' ([], _) ([], _) = ([], 0)
countSplitInv' (xs, _) ([], _) = (xs, 0)
countSplitInv' ([], _) (xs, _) = (xs, 0)
countSplitInv' (x : xs, nx) (y : ys, ny)
    | x > y     = (y : sortedY, nx + splitInvY)
    | otherwise = (x : sortedX, splitInvX)
    where
        (sortedX, splitInvX) = countSplitInv' (xs, pred nx) (y : ys, ny)
        (sortedY, splitInvY) = countSplitInv' (x : xs, nx) (ys, pred ny)

main :: IO ()
main = do
    contents <- getContents
    print $ inversions (map read (lines contents) :: [Int])

How could I write this code in a way that is more idiomatic, reduces the amount of repetition, and reduces the amount of data being copied?

wei2912
  • 1.2k
  • 8
  • 24