haskell中的合并排序进入无限循环

时间:2012-11-25 22:35:07

标签: haskell

大家好我试图在haskel中重现合并排序,这是我的代码:

-- merge
merge :: (Ord a) => [a] -> [a] -> [a]
merge [] [] = []
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys)
  | x <= y = x:(merge xs (y:ys))
  | otherwise = y:(merge (x:xs) ys)

-- split
splitIn2 :: (Ord a) => [a] -> ([a],[a])
splitIn2 [] = ([],[])
splitIn2 xs = splitAt ((length xs `div` 2)+1) xs

-- msort
msort :: (Ord a) => [a] -> [a]
msort [] = []
msort [x] = [x]
msort (xs) = merge (msort as) (msort bs)
    where (as,bs) = splitIn2 xs

它在ghc上编译,适用于:

*Main> msort([])
[]
*Main> msort([1])
[1]

然而它没有正常工作,因为它开始无限循环(至少这是我的想法)并且它不会打印任何东西。

我认为这是因为我不会像在其他递归实验中那样删除列表中的元素,有什么建议吗?

2 个答案:

答案 0 :(得分:8)

问题在于length xs == 2

(length xs `div` 2) + 1
= (2 `div` 2) + 1
= 1 + 1
= 2

splitAt 2 xs返回(xs, [])。由于第一个列表的长度仍为2msort会在无限循环中再次试用splitIn2

要解决这个问题,你可以简单地摆脱+1;这是完全没必要的。您可以 从splitAt 0 [] = ([], [])开始,也消除了空列表的特殊情况。

splitIn2 xs = splitAt (length xs `div` 2) xs

答案 1 :(得分:2)

*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3,0],[5,6])

经过小幅改动(删除+1):

splitIn2 xs = splitAt ((length xs `div` 2)) xs

有效:

*Main> splitIn2 [1, 2, 3, 0, 5, 6]
([1,2,3],[0,5,6])
*Main> msort [1, 2, 3, 0, 5, 6]
[0,1,2,3,5,6]