2011-03-11 6 views
6

저는 하스켈을 배우는 중이며 기수 정렬 함수를 작성했습니다. 올바르게 작동하는 것 같지만 문제는 메모리가 비효율적이라는 것입니다. ghc로 컴파일하면, 메모리는 이미 10000 개 요소의 입력리스트로 500MB가 넘습니다.하스켈의 기수 정렬 최적화

다음 알고리즘/코드가 어떻게 속도와 메모리면에서 더 효율적으로 개선 될 수 있는지 묻고 싶습니다. 가장 좋은 곳은 무엇입니까? ++은 O (N) 인과 카피마다 첫번째 인수로 주어진리스트 때문에

import System.Random 

-- radixsort for positive integers. uses 10 buckets 
radixsort :: [Int] -> [Int] 
radixsort [] = [] 
radixsort xs = 
    -- given the data, get the number of passes that are required for sorting 
    -- the largest integer 
    let maxPos = floor ((log (fromIntegral (foldl max 0 xs))/log 10) + 1) 

     -- start sorting from digit on position 0 (lowest position) to position 'maxPos' 
     radixsort' ys pos 
     | pos < 0 = ys 
     | otherwise = let sortedYs = radixsort' ys (pos - 1) 
          newBuckets = radixsort'' sortedYs [[] | i <- [1..10]] pos 
         in [element | bucket <- newBuckets, element <- bucket] 

     -- given empty buckets, digit position and list, sort the values into 
     -- buckets 
     radixsort'' []  buckets _ = buckets 
     radixsort'' (y:ys) buckets pos = 
      let digit = div (mod y (10^(pos + 1))) (10^pos) 
       (bucketsBegin, bucketsEnd) = splitAt digit buckets 
       bucket = head bucketsEnd 
       newBucket = bucket ++ [y] 
      in radixsort'' ys (bucketsBegin ++ [newBucket] ++ (tail bucketsEnd)) pos 
    in radixsort' xs maxPos 

-- get an random array given an seed 
getRandIntArray :: Int -> [Int] 
getRandIntArray seed = (randomRs (0, div (maxBound :: Int) 2) (mkStdGen seed)) 

main = do 
     value <- (\x -> return x) (length (radixsort (take 10000 (getRandIntArray 0)))) 
     print value 
+1

IO 모나드에서 배열을 사용 해본 적이 있습니까? – Gabe

+0

하스켈의 기본 사항에 익숙해 짐과 동시에 다른 데이터 유형을 확실히 확인해 보겠습니다. – Timo

+0

'maxPos'에서'foldl' 대신'foldl'을 사용해야합니다. 또한'floor (x + 1)'이'ceiling x'로 더 잘 표현되어 있지 않습니까? –

답변

6

주요 문제는, 함수 radixsort''이다.

pack (-1) r' _ = r' 
pack n r' relems = 
    let getn = (map snd) . (filter ((n==) . fst)) 
    in pack (n - 1) ((getn relems):r') relems 
radixsort'' elems pos = 
    let digit = \y -> div (mod y (10^(pos + 1))) (10^pos) 
     relems = zip (map digit elems) elems 
    in pack 9 [] relems 
+0

그 점을 지적하고 자신의 솔루션을 제공해 주셔서 감사합니다. 값을 버킷으로 정렬하는 것이 얼마나 교묘하게 처리되었는지 정말 좋아합니다. 배워야 할 것이 많습니다. – Timo

+2

'++'는 * O (n) *입니다. 여기서'n '은 첫 번째 목록의 길이입니다. 이를 사용하면 * O (n) * 개를 기대할 수있는 * O (n^2) * 알고리즘이 생길 수 있습니다. – luqui

+0

예, 너무 빨리 작성해서 죄송합니다. 그러나 질문에서 그것은 2 차 알고리즘으로 이어지는 여러 번 사용됩니다. (결정된) – Kru