|
| 1 | +# Haskell Skew Heap |
| 2 | + |
| 3 | +A Skew Heap node is defined as: |
| 4 | +```haskell |
| 5 | +data SkewHeap a = Empty | SkewNode a (SkewHeap a) (SkewHeap a) deriving (Show) |
| 6 | +``` |
| 7 | + |
| 8 | +The merge function is defined as an inline function named `+++`. |
| 9 | +Note the requirement that the data type stored in the heap must |
| 10 | +implement the Ord interface: |
| 11 | +```haskell |
| 12 | +(+++) :: Ord a => SkewHeap a -> SkewHeap a -> SkewHeap a |
| 13 | +heap1@(SkewNode x1 l1 r1) +++ heap2@(SkewNode x2 l2 r2) |
| 14 | + | x1 <= x2 = SkewNode x1 (heap2 +++ r1) l1 |
| 15 | + | otherwise = SkewNode x2 (heap1 +++ r2) l2 |
| 16 | +Empty +++ heap = heap |
| 17 | +heap +++ Empty = heap |
| 18 | +``` |
| 19 | + |
| 20 | +To extract the minimum value, you receive both the minimum value |
| 21 | +and the updated heap with the item removed. |
| 22 | +```haskell |
| 23 | +extractMin Empty = Nothing |
| 24 | +extractMin (SkewNode x l r ) = Just (x , l +++ r ) |
| 25 | +``` |
| 26 | + |
| 27 | +The `singleton` function creates a Skew Heap containing only |
| 28 | +one value. |
| 29 | +```haskell |
| 30 | +singleton :: Ord a => a -> SkewHeap a |
| 31 | +singleton x = SkewNode x Empty Empty |
| 32 | +``` |
| 33 | + |
| 34 | +In addition to these functions, there are some utility functions to |
| 35 | +convert to and from lists: |
| 36 | +```haskell |
| 37 | +toList :: Ord a => SkewHeap a -> [a] |
| 38 | +toList h = toList' (extractMin h) [] |
| 39 | + |
| 40 | +toList' :: Ord a => Maybe (a,SkewHeap a) -> [a] -> [a] |
| 41 | +toList' Nothing acc = reverse acc |
| 42 | +toList' (Just (v, h2)) acc = toList' (extractMin h2) (v:acc) |
| 43 | + |
| 44 | +fromList :: Ord a => [a] -> SkewHeap a |
| 45 | +fromList l = foldl' (+++) Empty $ map singleton l |
| 46 | +``` |
| 47 | + |
| 48 | +Finally, there are two examples of creating a Skew Heap from a list |
| 49 | +of numbers: |
| 50 | +```haskell |
| 51 | +fooHeap = fromList [1..10] |
| 52 | +barHeap = fromList [9,2,5,7,1,10,8,3,6,4] |
| 53 | +``` |
| 54 | + |
| 55 | +Here is an example session that displays one of the default heaps |
| 56 | +and then converts it into a list, which will be sorted: |
| 57 | +```shell |
| 58 | +$ ghci SkewHeap.hs |
| 59 | +GHCi, version 8.10.7: https://www.haskell.org/ghc/ :? for help |
| 60 | +[1 of 1] Compiling SkewHeap ( SkewHeap.hs, interpreted ) |
| 61 | +Ok, one module loaded. |
| 62 | +*SkewHeap> fooHeap |
| 63 | +SkewNode 1 (SkewNode 2 (SkewNode 6 (SkewNode 10 Empty Empty) Empty) (SkewNode 4 (SkewNode 8 Empty Empty) Empty)) (SkewNode 3 (SkewNode 5 (SkewNode 9 Empty Empty) Empty) (SkewNode 7 Empty Empty)) |
| 64 | +*SkewHeap> toList fooHeap |
| 65 | +[1,2,3,4,5,6,7,8,9,10] |
| 66 | +*SkewHeap> |
| 67 | +``` |
| 68 | + |
| 69 | +To demonstrate Haskell type classes, here is another data item that |
| 70 | +can be stored in a Skew Heap (this is in `heaptest.hs`): |
| 71 | +```haskell |
| 72 | +data Thing = Thing String Int |
| 73 | + deriving Show |
| 74 | +``` |
| 75 | + |
| 76 | +In order to store something of type `Thing` in a Skew Heap, you need |
| 77 | +to implement the `Ord` type class for it, as well as `Eq`. Note that |
| 78 | +the compare function reverses the arguments, meaning that the Skew |
| 79 | +Heap will actually return the maximum value in the heap instead of |
| 80 | +the minimum: |
| 81 | +```haskell |
| 82 | +instance Eq Thing where |
| 83 | + (==) (Thing _ i) (Thing _ j) = i == j |
| 84 | + |
| 85 | +instance Ord Thing where |
| 86 | + compare (Thing _ i) (Thing _ j) = compare j i |
| 87 | +``` |
| 88 | + |
| 89 | +Here is a list of some example data: |
| 90 | +```haskell |
| 91 | +things = [ Thing "Curly" 30, Thing "Moe" 100, Thing "Joe" 5, |
| 92 | + Thing "Curly Joe" 15, Thing "Shemp" 50, Thing "Larry" 85 ] |
| 93 | + |
| 94 | +``` |
| 95 | + |
| 96 | +Here is an example session that converts this list of things into |
| 97 | +a skew heap, and then converts that back into a list: |
| 98 | + |
| 99 | +```shell |
| 100 | +$ ghci heaptest.hs |
| 101 | +GHCi, version 8.10.7: https://www.haskell.org/ghc/ :? for help |
| 102 | +[1 of 2] Compiling SkewHeap ( SkewHeap.hs, interpreted ) |
| 103 | +[2 of 2] Compiling Main ( heaptest.hs, interpreted ) |
| 104 | +Ok, two modules loaded. |
| 105 | +*Main> let sh = fromList things |
| 106 | +*Main> sh |
| 107 | +SkewNode (Thing "Moe" 100) (SkewNode (Thing "Larry" 85) (SkewNode (Thing "Curly" 30) (SkewNode (Thing "Curly Joe" 15) Empty Empty) Empty) Empty) (SkewNode (Thing "Shemp" 50) (SkewNode (Thing "Joe" 5) Empty Empty) Empty) |
| 108 | +*Main> toList sh |
| 109 | +[Thing "Moe" 100,Thing "Larry" 85,Thing "Shemp" 50,Thing "Curly" 30,Thing "Curly Joe" 15,Thing "Joe" 5] |
| 110 | +*Main> |
| 111 | +``` |
0 commit comments