Advertisement
Yurry

Haskell Huffman

Dec 1st, 2014
210
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import Data.List
  2. import qualified Data.Map.Strict as M
  3. import Data.Monoid
  4. import Data.Ord
  5.  
  6. -- |Queue datatype and operations ----
  7.  
  8. data Queue a = Queue [a] [a]
  9.     deriving Show
  10.  
  11. empty = Queue [] []
  12.  
  13. push x (Queue xs ys) = Queue (x:xs) ys
  14.  
  15. pop (Queue [] []) = Nothing
  16. pop (Queue xs []) = pop (Queue [] (reverse xs))
  17. pop (Queue xs (x:ys)) = Just (x, Queue xs ys)
  18.  
  19. fromList :: [a] -> Queue a
  20. fromList = foldr push empty
  21.  
  22. fromOrderedList :: [a] -> Queue a
  23. fromOrderedList xs = Queue [] xs
  24.  
  25. distribution :: Ord a => [a] -> [(a, Int)]
  26. distribution str = sortBy (comparing snd) $ map (\g@(x:_) -> (x, length g)) . group . sort $ str where
  27.  
  28. takeMins :: (a -> a -> Ordering ) -> Int -> Queue a -> Queue a -> ([a], Queue a, Queue a)
  29. takeMins f i xs ys = go i [] xs ys where
  30.     go 0 acc xs ys = (acc, xs, ys)
  31.     go i acc xs ys = let i' = i - 1 in case (pop xs, pop ys) of
  32.        (Nothing, Nothing) -> (acc, xs, ys)
  33.        (Just (x, xs'), Nothing) -> go i' (x:acc) xs' ys
  34.         (Nothing, Just (y, ys')) -> go i' (y:acc) xs ys'
  35.        (Just (x, xs'), Just (y, ys')) -> case f x y of
  36.            LT -> go i' (x:acc) xs' ys
  37.            _  -> go i' (y:acc) xs ys'
  38.  
  39. -- |The Huffman itself ----
  40.  
  41. type Weight = Float
  42. data Tree a
  43.    = Leaf { weight :: Weight, sym :: a }
  44.    | Internal { weight :: Weight, left, right :: Tree a }
  45.    deriving Show
  46.  
  47. combine :: Tree a -> Tree a -> Tree a
  48. combine n1 n2 = Internal (weight n1 + weight n2) n1 n2
  49.  
  50. buildCodeTree :: (Ord a) => [a] -> Tree a
  51. buildCodeTree str = go start empty where
  52.    start = fromOrderedList $ map f $ distribution str
  53.    f (x, c) = Leaf w x where
  54.        w = fromIntegral c / l
  55.    l = fromIntegral $ length str
  56.    go xs ys = case takeMins (comparing weight) 2 xs ys of
  57.        ([x], _, _) -> x
  58.        ([x, y], xs', ys') -> go xs' $ push (combine x y) ys'
  59.        (_, xs', ys') -> error "Empty queues"
  60.  
  61. type CodeMap a = M.Map a [Bool]
  62.  
  63. buildCodeValues :: Ord a => Tree a -> CodeMap a
  64. buildCodeValues tree = go [] tree where
  65.    go pref (Leaf _ c) = M.singleton c (reverse pref)
  66.    go pref (Internal _ l r) = M.union
  67.        (go (False:pref) l)
  68.        (go (True:pref) r)
  69.  
  70. buildCodeTable = buildCodeValues . buildCodeTree
  71.  
  72. compress :: CodeMap Char -> String -> String
  73. compress cv str = concatMap (showBin . (cv M.!)) str where
  74.    showBin = map (\x -> if x then '1' else '0')
  75.  
  76. compressText :: String -> String
  77. compressText str = compress cv str where
  78.    cv = buildCodeTable str
  79.  
  80. calcProfit :: String -> Float
  81. calcProfit str = fromIntegral comprLen / fromIntegral initLen where
  82.    cv = buildCodeTable str
  83.    initEntr = ceiling $ logBase 2 $ fromIntegral $ length $ M.keys cv
  84.    initLen = initEntr * length str
  85.    comprLen = length $ compress cv str
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement