Haskell使用两个合并函数asc和desc合并排序

时间:2013-04-06 11:21:48

标签: haskell mergesort

我想使用合并排序算法。 mergeSort 是等待合并功能作为第一个参数的主要功能。有谁有想法,在我的情况下问题在哪里?非常感谢你提前。

mergeSort xs = merge xs
mergeDesc xs = reverse (mergeAsc xs)
mergeAsc [] = []
mergeAsc [x] = [x]
mergeAsc xs = merge (mergeAsc top) (mergeAsc bottom) where (top, bottom) = splitAt (length xs `div` 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) | x <= y    = x : merge xs (y:ys)
                    | otherwise = y : merge (x:xs) ys

1 个答案:

答案 0 :(得分:5)

为您的函数添加类型签名,然后问题就变得很明显了:

mergeAsc, mergeDesc :: Ord a => [a] -> [a]

mergeDesc xs = reverse (mergeAsc xs)
mergeAsc [] = []
mergeAsc [x] = [x]
mergeAsc xs = merge (mergeAsc top) (mergeAsc bottom) where (top, bottom) = splitAt (length xs `div` 2) xs

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

因此,如果您将mergeSort定义为merge,那么当您真正希望它订购单个列表时,它只是合并两个有序列表的函数。您可以使用

实现这一目标
mergeSort xs = mergeAsc xs

或简单而且最好,

mergeSort = margeAsc

请注意,mergeDesc并不是很好:首先按错误的顺序对列表进行排序,然后将其反转?在Haskell中,您希望您的算法足够灵活,可以自行处理不同排序的内容。所以你要定义

mergeSortBy :: (a->a->Ordering) -> [a] -> [a]
mergeSortBy cmp = mSort
 where 
       mSort [] = []
       mSort [x] = [x]
       mSort xs = merge (mSort top) (mSort bottom)
        where (top, bottom) = splitAt (length xs `quot` 2) xs

       merge [] ys = ys
       merge xs [] = xs
       merge (x:xs) (y:ys) = case x`cmp`y of
          LT  -> x : merge xs (y:ys)
          _   -> y : merge (x:xs) ys

然后,您只需定义mergeSort = mergeSortBy comparemergeSortDesc = mergeSortBy (flip compare)

同时观察如何使merge本地函数阻止您在实现中出现的错误。


  

它说应该声明为:mergeSort ::([a] - &gt; [a] - &gt; [a]) - &gt; [a] - &gt; [a]作为接受合并函数作为第一个参数的函数...

这很奇怪,它不应该被称为mergeSort,而是sortWithMerge或其他东西。无论如何,这样做很简单:只需抛出cmp(仅在merge子函数中使用!)并将其替换为参数而不是在本地定义。

sortWithMerge :: ([a]->[a]->[a]) -> [a] -> [a]
sortWithMerge merger = mSort
 where 
       mSort [] = []
       mSort [x] = [x]
       mSort xs = merger (mSort top) (mSort bottom)
        where (top, bottom) = splitAt (length xs `quot` 2) xs