Sorting haskell中整数的快速排序
haskell库中是否有函数可以在O(n)时间内对整数进行排序??[通过,O(n)我的意思是比比较排序快,并且特定于整数] 基本上,我发现下面的代码需要花费大量时间进行排序(与不进行排序的列表求和相比):Sorting haskell中整数的快速排序,sorting,haskell,int,Sorting,Haskell,Int,haskell库中是否有函数可以在O(n)时间内对整数进行排序??[通过,O(n)我的意思是比比较排序快,并且特定于整数] 基本上,我发现下面的代码需要花费大量时间进行排序(与不进行排序的列表求和相比): 这是从Richard Bird的书《函数算法设计的珍珠》(尽管我不得不对它进行了一些编辑,因为书中的代码并没有完全按照编写的那样编译) 导入数据.数组(数组、accumArray、assocs) 排序::[Int]->[Int] sort xs=concat[replicate kx |(x,
这是从Richard Bird的书《函数算法设计的珍珠》(尽管我不得不对它进行了一些编辑,因为书中的代码并没有完全按照编写的那样编译)
导入数据.数组(数组、accumArray、assocs)
排序::[Int]->[Int]
sort xs=concat[replicate kx |(x,k)使用数组对数字进行排序是减少内存使用的正确方法
但是,当maximum xs-minimum xs>(maxBound::Int)
时,使用列表的最大值和最小值作为边界可能会导致超过内存使用量,甚至运行时失败
因此,我建议将列表内容写入一个未绑定的可变数组,对该数组进行排序(例如,使用快速排序),然后再次从中构建列表
import System.Random
import Control.DeepSeq
import Data.Array.Base (unsafeRead, unsafeWrite)
import Data.Array.ST
import Control.Monad.ST
myqsort :: STUArray s Int Int -> Int -> Int -> ST s ()
myqsort a lo hi
| lo < hi = do
let lscan p h i
| i < h = do
v <- unsafeRead a i
if p < v then return i else lscan p h (i+1)
| otherwise = return i
rscan p l i
| l < i = do
v <- unsafeRead a i
if v < p then return i else rscan p l (i-1)
| otherwise = return i
swap i j = do
v <- unsafeRead a i
unsafeRead a j >>= unsafeWrite a i
unsafeWrite a j v
sloop p l h
| l < h = do
l1 <- lscan p h l
h1 <- rscan p l1 h
if (l1 < h1) then (swap l1 h1 >> sloop p l1 h1) else return l1
| otherwise = return l
piv <- unsafeRead a hi
i <- sloop piv lo hi
swap i hi
myqsort a lo (i-1)
myqsort a (i+1) hi
| otherwise = return ()
genlist gen = runST $ do
arr <- newListArray (0,2^22-1) $ take (2^22) (randoms gen)
myqsort arr 0 (2^22-1)
let collect acc 0 = do
v <- unsafeRead arr 0
return (v:acc)
collect acc i = do
v <- unsafeRead arr i
collect (v:acc) (i-1)
collect [] (2^22-1)
main = do
gen <- newStdGen
putStrLn $ show $ sum $ genlist gen
导入系统。随机
进口管制.DeepSeq
导入Data.Array.Base(未建议、未建议写入)
导入Data.Array.ST
进口管制站
myqsort::stus数组Int->Int->Int->Int->sts()
麦格索特酒店
|lov> p>我会考虑使用向量而不是列表,因为列表中每个元素都有很多开销,而未装箱的向量基本上只是一个相邻的字节块。包包含各种排序算法,你可以使用它,包括,我期望在你的情况下应该做的很好。
下面是一个简单的例子,不过如果您计划对结果进行进一步处理,最好将结果保持为向量形式
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Algorithms.Radix as R
sort :: [Int] -> [Int]
sort = V.toList . V.modify R.sort . V.fromList
此外,我怀疑您的示例的运行时间中有很大一部分来自随机数生成器,因为标准生成器的性能并不完全为人所知。您应该确保只对排序部分进行计时,如果您的程序中需要大量随机数,Hacka上有更快的生成器ge.O(n)
排序?我想您可以尝试实现。比较排序的复杂性不能低于O(n*log n)
。由于范围有限,您可以使用桶排序(但这不会减少此处的内存使用;)。你有没有试过在上面构建一个数据.IntSet
和toList
?使用Data.IntSet大约需要24秒,所以看起来确实更快,但是内存占用是320 MB!![genlist gen=id$!!toList$!!(fromList$!!take(2^22)((randoms gen):[Int])::IntSet)
]@DanielFischer:关于代码黑客或算法有什么想法可以帮助减少内存占用或以某种方式强制垃圾收集吗?我尝试了IntMap
和Map
(由于可能存在重复,所以集合不好),这对空间或时间都没有多大帮助。我能提供的最好方法是在STUArray
上进行快速排序。排序速度更快,而且只需要很少的内存。但是,最终列表需要大量内存,无论您如何排序。可能是因为您稍后添加时,它与列表中的max元素呈线性关系(我正在使用Int64)是的。而且,重新阅读您的原始问题,我也不确定这是否有特别小的内存占用:)这就是我的系统挂起的原因:)@Karan这被称为“计数排序”顺便说一句。根据您的情况,您可能更喜欢将排序结果保留为RLE格式(如果你的范围较短,那么你会有更多的副本)。但是这里你的范围对于数组Int
来说太宽了(而且你不需要调用最大值,你事先知道你的范围)。@WillNess:what's RLE?(维基百科在图形中谈到了运行长度)惊人的代码,它运行了大约7.5秒,我甚至没有看到32MB的使用量(正在通过top
进行监控)谢谢,@hammar.完全分心了,没有注意到。这将需要我一点时间来处理,但我们仍然可以在不使用可变事物的情况下完成这项工作;我指的是一个排序函数,它做了一些事情并将其丢弃,因为它以后不再需要它,并且只使用内存O(n)(对于函数范式而言)??@WillNess:我指的是在分配新内存时对旧结构进行垃圾收集(因此存在线性内存使用);但是,是的,编译器/GC自动推断破坏性更新(特别是在数组上的“/”函数等明显情况下)会非常酷@Karan顺便说一句,注意Daniel的qsort代码只适用于随机输入(这里有:)。作为练习,您可以将其更改为(1)随机选取轴,(2)使用三向分区(即,将等号与较小和较大的等号分开,然后您不需要对等号进行排序).我不知道如何做第一个。但是这可能会使它变慢,在这里你不需要这些更改,因为你的输入是随机的。除了Daniel指出的可变数组,这是最好的,thanx@DanielFischer:Introsort?在上找不到它hackage@Karan注意,这也使用了引擎盖下的可变结构t在Data.Vector.Algorithms.Intro
中,也在Vector Algorithms
软件包中。@DanielFischer:哇,不错,用了不到9秒的时间,你上一篇包含大量代码的帖子吓了我一跳,但这看起来是个不错的选择wrapper@DanielFischer哈马尔:有没有关于在哈斯克尔中使用这些向量/可变数组的好教程(不是通常的wikibook/Haskell Wiki)?
import Data.Array(Array,accumArray,assocs)
sort :: [Int] -> [Int]
sort xs = concat [replicate k x | (x,k) <- assocs count]
where count :: Array Int Int
count = accumArray (+) 0 range (zip xs (repeat 1))
range = (0, maximum xs)
import System.Random
import Control.DeepSeq
import Data.Array.Base (unsafeRead, unsafeWrite)
import Data.Array.ST
import Control.Monad.ST
myqsort :: STUArray s Int Int -> Int -> Int -> ST s ()
myqsort a lo hi
| lo < hi = do
let lscan p h i
| i < h = do
v <- unsafeRead a i
if p < v then return i else lscan p h (i+1)
| otherwise = return i
rscan p l i
| l < i = do
v <- unsafeRead a i
if v < p then return i else rscan p l (i-1)
| otherwise = return i
swap i j = do
v <- unsafeRead a i
unsafeRead a j >>= unsafeWrite a i
unsafeWrite a j v
sloop p l h
| l < h = do
l1 <- lscan p h l
h1 <- rscan p l1 h
if (l1 < h1) then (swap l1 h1 >> sloop p l1 h1) else return l1
| otherwise = return l
piv <- unsafeRead a hi
i <- sloop piv lo hi
swap i hi
myqsort a lo (i-1)
myqsort a (i+1) hi
| otherwise = return ()
genlist gen = runST $ do
arr <- newListArray (0,2^22-1) $ take (2^22) (randoms gen)
myqsort arr 0 (2^22-1)
let collect acc 0 = do
v <- unsafeRead arr 0
return (v:acc)
collect acc i = do
v <- unsafeRead arr i
collect (v:acc) (i-1)
collect [] (2^22-1)
main = do
gen <- newStdGen
putStrLn $ show $ sum $ genlist gen
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Algorithms.Radix as R
sort :: [Int] -> [Int]
sort = V.toList . V.modify R.sort . V.fromList