-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSeqQueue.hs
123 lines (102 loc) · 3.56 KB
/
SeqQueue.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
{-# LANGUAGE TupleSections #-}
-----------------------------------------------------------------------------
-- | A min-max priority queue implemented using a min-max heap
-- backed by a 'Seq', for benchmarking purposes.
module SeqQueue (fromList, pollMin) where
import qualified Data.Foldable as Foldable
import Data.Maybe (catMaybes, fromJust)
import qualified Data.Sequence as Seq
import Data.Sequence (Seq, (|>), ViewL((:<)), ViewR((:>)))
import Math.NumberTheory.Logarithms (intLog2)
import Prelude hiding (init)
type SeqQueue a = Seq a
type Index = Int
empty :: SeqQueue a
empty = Seq.empty
fromList :: Ord a => [a] -> SeqQueue a
fromList = Foldable.foldr insert empty
size :: SeqQueue a -> Int
size = Seq.length
insert :: Ord a => a -> SeqQueue a -> SeqQueue a
insert a q = bubbleUp (size q') a q'
where q' = q |> a
peekMin :: SeqQueue a -> Maybe a
peekMin q
| hd :< _ <- Seq.viewl q = Just hd
| otherwise = Nothing
deleteMin :: Ord a => SeqQueue a -> SeqQueue a
deleteMin q
| init :> an <- Seq.viewr q =
trickleDown 1 an (update 1 an init)
| otherwise = empty
pollMin :: Ord a => SeqQueue a -> Maybe (a, SeqQueue a)
pollMin q = (,) <$> peekMin q <*> pure (deleteMin q)
(!) :: Seq a -> Index -> a
(!) xs i = fromJust $ Seq.lookup (i-1) xs
(!?) :: Seq a -> Index -> Maybe a
(!?) xs i = Seq.lookup (i-1) xs
bubbleUp :: Ord a => Index -> a -> SeqQueue a -> SeqQueue a
bubbleUp idx a q
| idx == 1 = q
| isMinLevel idx =
if a > parent
then bubbleUpMax parentIdx a (swap parentIdx parent idx a q)
else bubbleUpMin idx a q
| otherwise =
if a < parent
then bubbleUpMin parentIdx a (swap parentIdx parent idx a q)
else bubbleUpMax idx a q
where
parentIdx = idx `div` 2
parent = q ! parentIdx
bubbleUpMin :: Ord a => Index -> a -> SeqQueue a -> SeqQueue a
bubbleUpMin idx a q
| idx < 4 = q
| a < grandParent = bubbleUpMin grandParentIdx a (swap grandParentIdx grandParent idx a q)
| otherwise = q
where
grandParentIdx = idx `div` 4
grandParent = q ! grandParentIdx
bubbleUpMax :: Ord a => Index -> a -> SeqQueue a -> SeqQueue a
bubbleUpMax idx a q
| idx < 4 = q
| a > grandParent = bubbleUpMax grandParentIdx a (swap grandParentIdx grandParent idx a q)
| otherwise = q
where
grandParentIdx = idx `div` 4
grandParent = q ! grandParentIdx
isMinLevel :: Int -> Bool
isMinLevel = even . intLog2
swap :: Index -> a -> Index -> a -> SeqQueue a -> SeqQueue a
swap idx1 a1 idx2 a2 = update idx1 a2 . update idx2 a1
trickleDown :: Ord a => Index -> a -> SeqQueue a -> SeqQueue a
trickleDown idx a q
| fmly@(_:_) <- family idx q =
let (a',idx') = Foldable.minimum fmly
in if a' >= a
then q
else if idx' > 2 * idx + 1
then let q' = swap idx' a' idx a q
parentIdx = idx' `div` 2
parent = fst . fromJust $ Foldable.find ((== parentIdx) . snd) fmly
in if a > parent then trickleDown idx' parent (swap parentIdx parent idx' a q') else trickleDown idx' a q'
else swap idx' a' idx a q
| otherwise = q
family :: Index -> SeqQueue a -> [(a, Index)]
family idx q = catMaybes
[ (,l) <$> (q !? l)
, (,r) <$> (q !? r)
, (,ll) <$> (q !? ll)
, (,lr) <$> (q !? lr)
, (,rl) <$> (q !? rl)
, (,rr) <$> (q !? rr)
]
where
l = idx * 2
r = l + 1
ll = idx * 4
lr = ll + 1
rl = ll + 2
rr = ll + 3
update :: Int -> a -> SeqQueue a -> SeqQueue a
update x = Seq.update (x-1)