Sorting 合并排序的这个实现好吗?
我昨晚刚开始学习Haskell,以前从未使用过函数式编程语言。 我只是想知道我的合并排序的实现是好是坏,到底是好是坏。 也许这甚至是错误的——它确实进行排序,但可能算法不是我所认为的合并排序 只要告诉我这里能改进的地方就行了。我个人认为这是一个非常清晰和简单的实现。 谢谢您的建议,下面是代码:)Sorting 合并排序的这个实现好吗?,sorting,haskell,merge,mergesort,Sorting,Haskell,Merge,Mergesort,我昨晚刚开始学习Haskell,以前从未使用过函数式编程语言。 我只是想知道我的合并排序的实现是好是坏,到底是好是坏。 也许这甚至是错误的——它确实进行排序,但可能算法不是我所认为的合并排序 只要告诉我这里能改进的地方就行了。我个人认为这是一个非常清晰和简单的实现。 谢谢您的建议,下面是代码:) merge[]ys=ys 合并xs[]=xs 合并xs ys=已排序:合并左-右 哪里 排序=如果头部(xs)(x:r,l))([],[])嘿,非常感谢您的精确反馈。恐怕我现在还不能完全理解,因为我还没
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
在其前面的表达式中绑定变量)。关于Haskell语法的更多信息,包括guards(带有where
的东西),可以在本章中找到| condition=value
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)) ([],[])