Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 合并排序的这个实现好吗?_Sorting_Haskell_Merge_Mergesort - Fatal编程技术网

Sorting 合并排序的这个实现好吗?

Sorting 合并排序的这个实现好吗?,sorting,haskell,merge,mergesort,Sorting,Haskell,Merge,Mergesort,我昨晚刚开始学习Haskell,以前从未使用过函数式编程语言。 我只是想知道我的合并排序的实现是好是坏,到底是好是坏。 也许这甚至是错误的——它确实进行排序,但可能算法不是我所认为的合并排序 只要告诉我这里能改进的地方就行了。我个人认为这是一个非常清晰和简单的实现。 谢谢您的建议,下面是代码:) merge[]ys=ys 合并xs[]=xs 合并xs ys=已排序:合并左-右 哪里 排序=如果头部(xs)(x:r,l))([],[])嘿,非常感谢您的精确反馈。恐怕我现在还不能完全理解,因为我还没

我昨晚刚开始学习Haskell,以前从未使用过函数式编程语言。 我只是想知道我的合并排序的实现是好是坏,到底是好是坏。 也许这甚至是错误的——它确实进行排序,但可能算法不是我所认为的合并排序

只要告诉我这里能改进的地方就行了。我个人认为这是一个非常清晰和简单的实现。 谢谢您的建议,下面是代码:)

merge[]ys=ys
合并xs[]=xs
合并xs ys=已排序:合并左-右
哪里
排序=如果头部(xs)<头部(ys),则头部(xs)或其他头部(ys)
左=如果头部(xs)头部(ys)然后尾部(ys)否则ys
msort[]=[]
msort[x]=[x]
msort xs=合并(msort left)(msort right)
哪里
左=取(div(长度xs)2)xs
右=下降(div(长度xs)2)xs

首先,我们可以使用模式匹配将merge重写得更优雅一些

merge [] ys = ys
merge xs [] = xs
merge xs@(x:xs1) ys@(y:ys1)
    | x <= y = x : merge xs1 ys
    | otherwise = y : merge xs ys1
这将在O(NlogN)时间内获得相同的合并排序。感觉不一样,因为您可能会使用命令式语言(如C)就地实现它(通过修改原始列表)。此版本的内存成本稍高,但它确实有它的优点-更容易推理,因此更易于维护,而且,除了算法本身之外,无需考虑其他任何事情,就可以很容易地实现,这正是一种好的编程语言应该为使用它的开发人员提供的

编辑1:

如果语法有点过多,下面是一些参考资料:

  • -带有
    @
    符号的位称为as模式。你会在那里找到的
  • let
    是一个关键字,用于声明要在其后面的表达式中使用的变量(而
    where
    在其前面的表达式中绑定变量)。关于Haskell语法的更多信息,包括guards(带有
    | condition=value
    的东西),可以在本章中找到
编辑2:

@is7s使用
foldr
,提出了一个更加简洁的
splitInHalves
版本:

编辑3:

下面是另一个答案,它提供了合并排序的另一种实现,该实现还具有以下特性:


希望这有助于并欢迎来到函数式编程的精彩世界

splitInHalves=foldr(\x(l,r)->(x:r,l))([],[])
嘿,非常感谢您的精确反馈。恐怕我现在还不能完全理解,因为我还没有阅读所有的语法(“let…in…”或“@”),但我会查找这些内容并尝试理解您的代码:)@is7s-是的,这更简洁,但对于FP的新手来说,我认为更详细的版本更适合初学者。@Nocta-哦,没问题。我添加了一些链接来解释使用的各种构造。
splitInHalves[x,y]=([x],[y])
大小写是多余的,不是吗?在这两行中,
sorted=
left=
,必须使用相同的比较;哦,对不起,刚才看到了那条评论。我想你是对的。如果我理解正确,这个小错误只会影响算法的稳定/不稳定属性,对吗?如果头(xs)或头(ys)相等,我取它们真的没有关系。不,在这两个相等的值中,你会完全去掉一个,在你的输出中有另外两个:
merge[(1,1),(2,1)][(1,2),(2,2)]=(1,2):merge[(2,1)][(1,2),(2,2)]
,对于只在第一个子元素上比较的成对数据类型。
merge [] ys = ys
merge xs [] = xs
merge xs@(x:xs1) ys@(y:ys1)
    | x <= y = x : merge xs1 ys
    | otherwise = y : merge xs ys1
msort [] = []
msort [x] = [x]
msort xs = merge (msort first) (msort second)
    where
        (first, second) = splitInHalves xs
        splitInHalves [] = ([], [])
        splitInHalves [x] = ([x], [])
        splitInHalves (x:y:xs) =
            let (xs1, ys1) = splitInHalves xs
            in  (x:xs1, y:ys1)
splitInHalves = foldr (\x (l,r) -> (x:r,l)) ([],[])