okasaki

Okasaki's Purely Functional Data Structures
Log | Files | Refs | LICENSE

commit a1e4d2e8a9d3b7476aad8ab80152cae96624ecf8
parent 2cf32a073a1b260c7c9f29b245b06339296c68b7
Author: Jared Tobin <jared@jtobin.ca>
Date:   Sat, 22 Nov 2014 21:42:21 +1300

Moar heap work.

Diffstat:
MBinomialHeap.hs | 67++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
AUnrankedBinomialHeap.hs | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MWeightBiasedLeftistHeap.hs | 12++++++++++--
3 files changed, 141 insertions(+), 3 deletions(-)

diff --git a/BinomialHeap.hs b/BinomialHeap.hs @@ -2,10 +2,16 @@ module BinomialHeap where -data Tree a = Node Int a [Tree a] +data Tree a = Node Int a [Tree a] deriving Show type Heap a = [Tree a] +empty :: Heap a +empty = [] + +isEmpty :: Heap a -> Bool +isEmpty = null + link :: Ord a => Tree a -> Tree a -> Tree a link t0@(Node r x0 c0) t1@(Node _ x1 c1) | x0 <= x1 = Node (succ r) x0 (t1 : c0) @@ -54,3 +60,62 @@ deleteMin ts = case removeMinTree ts of Nothing -> [] Just (Node _ _ ts0, ts1) -> merge (reverse ts0) ts1 +fromList :: Ord a => [a] -> Heap a +fromList = foldr insert empty + +-- exercise 3.5 (findMin without call to removeMinTree) +altFindMin :: Ord a => Heap a -> Maybe a +altFindMin [] = Nothing +altFindMin [t] = return $ root t +altFindMin (Node _ e _:ts) = do + alt <- altFindMin ts + return $ + if e < alt + then e + else alt + +-- exercise 3.7 (O(1) min in ocaml functor style) +class Heaplike h where + hEmpty :: h a + hIsEmpty :: h a -> Bool + hInsert :: Ord a => a -> h a -> h a + hFindMin :: Ord a => h a -> Maybe a + hDeleteMin :: Ord a => h a -> h a + + hFromList :: Ord a => [a] -> h a + hFromList = foldr hInsert hEmpty + +data ExplicitMinHeap h a = E | NE a (h a) deriving Show + +instance Heaplike h => Heaplike (ExplicitMinHeap h) where + hEmpty = E + + hIsEmpty E = True + hIsEmpty _ = False + + hInsert e E = NE e (hInsert e hEmpty) + hInsert e (NE m h) = NE (min e m) (hInsert e h) + + hFindMin E = Nothing + hFindMin (NE m _) = Just m + + hDeleteMin E = hEmpty + hDeleteMin (NE m0 h) = + let smaller = hDeleteMin h + in case hFindMin smaller of + Nothing -> NE m0 smaller + Just m1 -> NE (min m0 m1) smaller + +-- example +newtype BinomialHeap a = BinomialHeap { unwrap :: Heap a } deriving Show + +instance Heaplike BinomialHeap where + hEmpty = BinomialHeap empty + hIsEmpty = isEmpty . unwrap + hInsert e (BinomialHeap h) = BinomialHeap $ insert e h + hFindMin (BinomialHeap h) = findMin h + hDeleteMin (BinomialHeap h) = BinomialHeap $ deleteMin h + +altFromList :: Ord a => [a] -> ExplicitMinHeap BinomialHeap a +altFromList = hFromList + diff --git a/UnrankedBinomialHeap.hs b/UnrankedBinomialHeap.hs @@ -0,0 +1,65 @@ +{-# OPTIONS_GHC -Wall #-} + +module UnrankedBinomialHeap where + +-- exercise 3.6 (alternate-rank representation of binomial heaps) +data Tree a = Node a [Tree a] deriving Show + +type Heap a = [(Int, Tree a)] + +empty :: Heap a +empty = [] + +isEmpty :: Heap a -> Bool +isEmpty = null + +link :: Ord a => (Int, Tree a) -> (Int, Tree a) -> (Int, Tree a) +link (r, t0@(Node x0 c0)) (_, t1@(Node x1 c1)) + | x0 <= x1 = (succ r, Node x0 (t1 : c0)) + | otherwise = (succ r, Node x1 (t0 : c1)) + +root :: Tree a -> a +root (Node x _) = x + +insertTree :: Ord a => (Int, Tree a) -> Heap a -> Heap a +insertTree p [] = [p] +insertTree p0@(r0, _) ts@(p1@(r1, _):trees) + | r0 < r1 = p0 : ts + | otherwise = insertTree (link p0 p1) trees + +insert :: Ord a => a -> Heap a -> Heap a +insert x = insertTree (0, Node x []) + +merge :: Ord a => Heap a -> Heap a -> Heap a +merge ts [] = ts +merge [] ts = ts +merge ts0@(tree0:trees0) ts1@(tree1:trees1) + | fst tree0 < fst tree1 = tree0 : merge trees0 ts1 + | fst tree1 < fst tree0 = tree1 : merge ts0 trees1 + | otherwise = insertTree (link tree0 tree1) (merge trees0 trees1) + +removeMinTree :: Ord a => Heap a -> Maybe ((Int, Tree a), Heap a) +removeMinTree [] = Nothing +removeMinTree [p] = return (p, []) +removeMinTree (p0@(_, t):ts) = do + (p1@(_, tree), trees) <- removeMinTree ts + return $ + if root t < root tree + then (p0, ts) + else (p1, p0:trees) + +findMin :: Ord a => Heap a -> Maybe a +findMin ts = do + ((_, t), _) <- removeMinTree ts + return $ root t + +deleteMin :: Ord a => Heap a -> Heap a +deleteMin ts = case removeMinTree ts of + Nothing -> [] + Just ((r, Node _ ts0), ts1) -> + let lesser = zip (repeat (pred r)) (reverse ts0) + in merge lesser ts1 + +fromList :: Ord a => [a] -> Heap a +fromList = foldr insert empty + diff --git a/WeightBiasedLeftistHeap.hs b/WeightBiasedLeftistHeap.hs @@ -41,6 +41,14 @@ singleton e = Node e Leaf Leaf insert :: Ord a => a -> Heap a -> Heap a insert e = merge (singleton e) +findMin :: Heap a -> Maybe a +findMin Leaf = Nothing +findMin (Node e _ _) = return e + +deleteMin :: Ord a => Heap a -> Heap a +deleteMin Leaf = Leaf +deleteMin (Node _ l r) = merge l r + fromList :: Ord a => [a] -> Heap a fromList = foldr insert empty @@ -58,6 +66,6 @@ altMerge h0@(Node e0 l0 r0) h1@(Node e1 l1 r1) = Node e l r where | otherwise = second (`altMerge` h) branches -- exercise 3.4d (advantages of altMerge) --- - lazy environment ? --- - concurrent environment ? +-- - lazy environment (no buildup of thunks?) +-- - concurrent environment (more opportunity for concurrency?)