Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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
Haskell中的合并排序_Haskell_Performance_Mergesort - Fatal编程技术网

Haskell中的合并排序

Haskell中的合并排序,haskell,performance,mergesort,Haskell,Performance,Mergesort,我是Haskell的新手,我正在尝试在其中实现一些已知的算法 我已经在字符串上实现了合并排序。我对这个计划有点失望 与C和Java实现相比,我的Haskell实现的性能。 在我的机器(UbuntuLinux,1.8GHz)上,C(GCC4.3.3)以1.85秒对1000000个字符串进行排序, Java(JavaSE1.6.0_14)在3.68秒,Haskell(GHC6.8.2)在25.89秒。 对于较大的输入(10000个字符串),C需要21.81秒,Java需要59.68秒,Haskell

我是Haskell的新手,我正在尝试在其中实现一些已知的算法

我已经在字符串上实现了合并排序。我对这个计划有点失望 与C和Java实现相比,我的Haskell实现的性能。 在我的机器(UbuntuLinux,1.8GHz)上,C(GCC4.3.3)以1.85秒对1000000个字符串进行排序, Java(JavaSE1.6.0_14)在3.68秒,Haskell(GHC6.8.2)在25.89秒。 对于较大的输入(10000个字符串),C需要21.81秒,Java需要59.68秒,Haskell 开始交换,我宁愿在几分钟后停止程序

由于我是Haskell的新手,我想知道我的实现是否可以 提高时间/空间效率

提前感谢您的任何提示 乔治

我的实施:

merge :: [String] -> [String] -> [String]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys) = if x < y
                        then x : (merge xs (y:ys))
                        else y : (merge (x:xs) ys)

mergeSort :: [String] -> [String]
mergeSort xs = if (l < 2)
                 then xs
                 else merge h t
               where l = length xs
                     n = l `div` 2
                     s = splitAt n xs
                     h = mergeSort (fst s)
                     t = mergeSort (snd s)
merge::[String]->[String]->[String]
合并[]ys=ys
合并xs[]=xs
合并(x:xs)(y:ys)=如果x[String]
合并排序xs=if(l<2)
然后是xs
否则合并h t
其中l=长度xs
n=l`div`2
s=在n x处拆分
h=合并排序(fst s)
t=合并排序(snd s)

我不确定这是否是问题的原因,但请记住列表是一种顺序数据结构。特别是
length xs
splitAt n xs
都需要与列表长度成比例的时间量(
O(n)

在C和Java中,最有可能使用的是数组,这两种操作都需要固定的时间(
O(1)


编辑:回答您关于如何提高效率的问题,您也可以在Haskell中使用数组。

在Haskell中,字符串是一个惰性字符列表,其开销与任何其他列表相同。如果我记得2004年西蒙·佩顿·琼斯(Simon Peyton Jones)的一次演讲,GHC中的空间成本是每个字符40字节。对于苹果对苹果的比较,您可能应该进行排序,这是为了使性能与其他语言相当。

更好地分割列表以避免出现问题CesarB指出:

split []             = ([], [])
split [x]            = ([x], [])
split (x : y : rest) = (x : xs, y : ys)
                       where (xs, ys) = split rest

mergeSort []  = []
mergeSort [x] = [x]
mergeSort xs  = merge (mergesort ys) (mergesort zs)
                where (ys, zs) = split xs
编辑:已修复。

尝试此版本:

mergesort :: [String] -> [String]
mergesort = mergesort' . map wrap

mergesort' :: [[String]] -> [String]
mergesort' [] = []
mergesort' [xs] = xs
mergesort' xss = mergesort' (merge_pairs xss)

merge_pairs :: [[String]] -> [[String]]
merge_pairs [] = []
merge_pairs [xs] = [xs]
merge_pairs (xs:ys:xss) = merge xs ys : merge_pairs xss

merge :: [String] -> [String] -> [String]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
 = if x > y
        then y : merge (x:xs)  ys
        else x : merge  xs    (y:ys)

wrap :: String -> [String]
wrap x = [x]
  • 坏主意是先拆分列表。取而代之的是只列出一个成员列表。哈斯克尔很懒,这件事会在适当的时候完成的
  • 然后合并列表对,直到只有一个列表

  • 编辑:否决此答案的人:上述合并排序实现与ghc Data.List.sort中使用的算法相同,只是删除了cmp函数。ghc的作者可能是错的:-/

    ,但您可能不想使用它来表示字符串。诺曼·拉姆齐是对的:这就是
    数据。ByteString
    的作用。@alexey\r:我指的数组是用来替换[String],而不是用来替换字符串aka[Char]本身。替换字符串是一个单独的优化。谢谢你的提示。我不确定ByteString是否与String相同。据我所知,String::[Char]其中Char是一个unicode字符。另一方面,BytyString包含一个Word8字符串,即字节。然后我应该确保我的输入是每字符一个字节的编码,例如拉丁文1。否则,在评估字典顺序时,ByteString如何处理多字节字符?:“utf8字符串包提供了将utf8字符串编码到Word8列表和返回的操作,以及在不截断的情况下读取和写入utf8的操作。”@alexey\u r:代码中有两个错误。一是“x:y:xs”模式必须放在括号内。另一个是“:”和“$”的先例使您将“split xs”赋予函数“x:fst”@alexey\u r:我认为您的代码目前计算了两次“split xs”。更好地使用(ys,zs)=拆分xs。或splitxs=splitxs。因此,只有一个调用splitas a socialist作为一个社会主义者,我对“(mergesort$ys)”中多余的美元感到烦恼:)也改变了这一点(尽管不是社会主义者:)。这种split的实现使得创建稳定的排序算法变得困难(不可能)。顺便说一句,您在GHC中使用了什么编译标志?这并不是一个理想的实现。您不断地遍历每个子列表以查找其长度,这是不必要的。请参阅下面的Hynek-Pichi-Vychodil版本,以了解更懒惰且可能更快的版本。@Axman6-能否提供指向此算法的链接?或者引用?你应该使用“如果x是一个稳定的版本”“+1与快速排序相比,它分配了大量内存,因此我怀疑它是否仍被用作标准库函数。@EGDMITY:是的,它已于2009年12月24日被更好但仍然是合并排序实现所取代。所以我最初回答这个问题的时候是真的。无论如何,如果您有任何证据表明快速排序分配的内存更少或表现更好,请详细说明。为什么不看源代码而猜测呢?我的意思是,标准快速排序实现分配的内存比这里给出的实现少得多。至于你的最后一个问题——评测标准排序函数和你给定的实现,我不需要看代码就可以确定它们是不同的。