Arrays 普通数组上的Haskell快速排序-可能吗?
在自学haskell的过程中,我试图实现快速排序。为了方便起见,我将自己限制在ghc附带的包中,这就是为什么我使用数组而不是向量:Arrays 普通数组上的Haskell快速排序-可能吗?,arrays,haskell,quicksort,Arrays,Haskell,Quicksort,在自学haskell的过程中,我试图实现快速排序。为了方便起见,我将自己限制在ghc附带的包中,这就是为什么我使用数组而不是向量: import Data.Array type ArrayT = Array Int quickSort :: Ord t => ArrayT t -> ArrayT t quickSort a = rQuickSort (bounds a) a rQuickSort :: Ord t => (Int, Int) -> ArrayT t
import Data.Array
type ArrayT = Array Int
quickSort :: Ord t => ArrayT t -> ArrayT t
quickSort a = rQuickSort (bounds a) a
rQuickSort :: Ord t => (Int, Int) -> ArrayT t -> ArrayT t
rQuickSort (beg,end) arr | beg >= end = arr
rQuickSort (beg,end) arr =
rQuickSort (beg, pivIndex) . rQuickSort (pivIndex+1, end) $ parted
where
(pivoted, pivValue) = med3pivot (beg, end) arr
(parted , pivIndex) = partition (beg+1, end-1) pivoted pivValue
med3pivot :: Ord t => (Int, Int) -> ArrayT t -> (ArrayT t, t)
med3pivot (beg, end) =
let mid = (beg + end) `div` 2
in (\arr -> (arr,arr!mid))
. (\arr -> if arr!end < arr!mid then swap end mid arr else arr)
. (\arr -> if arr!mid < arr!beg then swap mid beg arr else arr)
. (\arr -> if arr!end < arr!beg then swap end beg arr else arr)
partition :: Ord t => (Int, Int) -> ArrayT t -> t -> (ArrayT t, Int)
partition (beg, end) arr piv =
let fw = findForward (piv <) (beg,end) arr
bw = findBackward (piv >) (beg,end) arr
in if fw >= bw then (arr, bw)
else partition (fw+1, bw-1) (swap fw bw arr) piv
findForward :: (t -> Bool) -> (Int, Int) -> ArrayT t -> Int
findForward _ (b,e) _ | b > e = b
findForward p (b,e) a = if p (a!b) then b else findForward p (b+1,e) a
findBackward :: (t -> Bool) -> (Int, Int) -> ArrayT t -> Int
findBackward _ (b,e) _ | b > e = e
findBackward p (b,e) a = if p (a!e) then e else findBackward p (b,e-1) a
swap :: Int -> Int -> ArrayT t -> ArrayT t
swap i j arr = arr // [(i, arr!j), (j, arr!i)]
mkArray :: [a] -> Array Int a
mkArray xs = listArray (0, length xs - 1) xs
我显然弄错了。我得到了大约8秒的运行时间,用于对10000个短bytestring数组进行排序,目前省略了驱动代码,因为这已经是一堆了。
我想我没有正确理解一般的惰性,以及数组拷贝发生的位置。任何指点都很感激
我找到了这个使用Array.ST的答案,但我仍然想知道我的代码出了什么问题。甚至可以像我正在尝试的那样,对普通数组进行就地排序吗?数组是一种不可变的数据类型,因此每次交换都要构造一个新的数组“spine”,尽管元素(即t类型的值)是共享的
您通常应该使用数组来计算诸如记忆表之类的东西,比如从其他语言翻译动态编程算法时,而不是像这样的顺序算法。当您使用相互引用的thunk填充元素,并且从索引中读取以计算并缓存该索引的元素时,数组工作得最好
获得实际就地排序的唯一方法是在ST或IO中使用可变数组类型。但是,我认为您也可以更有效地执行此不可变数组排序,方法是构造一系列条件交换,即排序网络,并仅将其应用于输入数组一次,以生成输出数组。数组是一种不可变的数据类型,因此您每次交换都要构造一个新数组“spine”,尽管元素(即t型值)是共享的
您通常应该使用数组来计算诸如记忆表之类的东西,比如从其他语言翻译动态编程算法时,而不是像这样的顺序算法。当您使用相互引用的thunk填充元素,并且从索引中读取以计算并缓存该索引的元素时,数组工作得最好
获得实际就地排序的唯一方法是在ST或IO中使用可变数组类型。但是,我认为你也可以更有效地进行不可变数组排序,通过构造一系列条件交换,即排序网络,只对输入数组应用一次,生成输出数组。除了Jon Purdy所说的,如果不使用随机数据透视或使用中间值中位数或类似值选择数据透视,它就不是快速排序。除了Jon Purdy所说的,如果不使用随机数据透视或使用中间值中位数或类似值选择数据透视,它就不是快速排序。