Import Upstream version 20180207
[hcoop/debian/mlton.git] / lib / mlton / heap / binary.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006, 2008 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 *
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
6 *)
7
8functor BinaryHeap (Key: BOUNDED_ORDER): HEAP =
9struct
10
11structure Array = ResizableArray
12structure Key = Key
13
14(*--------------------------------------------------------*)
15(* Element *)
16(*--------------------------------------------------------*)
17structure Element =
18 struct
19 datatype 'a t = T of {key: Key.t ref,
20 value: 'a,
21 index: int ref}
22 fun new(k, v, i) = T{key = ref k,
23 value = v,
24 index = ref i}
25 fun key(T{key, ...}) = !key
26 fun setKey(T{key, ...}, k) = key := k
27 fun value (T{value, ...}) = value
28 fun index (T{index, ...}) = !index
29 fun setIndex(T{index, ...}, i) = index := i
30 end
31structure Elt = Element
32
33(*--------------------------------------------------------*)
34(* Heap *)
35(*--------------------------------------------------------*)
36
37datatype 'a t = T of 'a Elt.t Array.t
38
39fun empty() = T (Array.fromList [])
40
41fun fixIndex(a, i) = Elt.setIndex(Array.sub(a, i), i)
42fun swap(a, i, j) = (Array.swap(a, i, j)
43 ; fixIndex(a, i)
44 ; fixIndex(a, j))
45
46fun isEmpty (T a) = Array.length a = 0
47
48fun parent(i: int) = (i - 1) div 2
49fun left(i: int) = 2 * i + 1
50fun right(i: int) = 2 * i + 2
51fun key(a, i) = Elt.key(Array.sub(a, i))
52fun keyOption(a, i) = Option.map(Array.subOption(a, i), Elt.key )
53
54fun siftUp(a, i) =
55 let fun siftUp i = if i = 0 then ()
56 else let val p = parent i
57 in if Key.<(key(a, i), key(a, p))
58 then (swap(a, i, p); siftUp p)
59 else ()
60 end
61 in siftUp i
62 end
63
64fun siftDown(a, i) =
65 let
66 fun siftDown i =
67 let val l = left i
68 val r = right i
69 in case keyOption(a, l) of
70 NONE => ()
71 | SOME kl =>
72 let val min = (case keyOption(a, r) of
73 NONE => l
74 | SOME kr => if Key.<(kl, kr)
75 then l else r)
76 in if Key.<(key(a, i), key(a, min)) then ()
77 else (swap(a, i, min); siftDown min)
78 end
79 end
80 in siftDown i
81 end
82
83fun new es =
84 let val a = Array.fromList (List.mapi (es, fn (i, (k, v)) =>
85 Elt.new (k, v, i)))
86 val start = (Array.length a) div 2
87 in Int.forDown (start, 0, fn i => siftDown (a, i))
88 ; T a
89 end
90
91fun isEmpty (T a) = Array.length a = 0
92
93fun foreach(T a, f) = Array.foreach(a, f)
94
95fun insert(T a, k, v) =
96 let val i = Array.length a
97 val e = Elt.new(k, v, i)
98 in Array.addToEnd(a, e)
99 ; siftUp(a, i)
100 ; e
101 end
102
103fun min (h as (T a)) =
104 if isEmpty h then Error.bug "min"
105 else Array.sub(a, 0)
106
107fun deleteMin (h as (T a)) =
108 if isEmpty h then Error.bug "deleteMin"
109 else Elt.value (if Array.length a = 1
110 then Array.deleteLast a
111 else let val min = Array.sub(a, 0)
112 in Array.update(a, 0, Array.deleteLast a)
113 ; fixIndex(a, 0)
114 ; siftDown(a, 0)
115 ; min
116 end)
117
118fun decreaseKey(T a, e, k) =
119 if Key.<(Elt.key e, k) then Error.bug "decreaseKey"
120 else (Elt.setKey(e, k); siftUp(a, Elt.index e))
121
122fun delete(h, e) = (decreaseKey(h, e, Key.smallest); deleteMin h; ())
123
124fun union(h, h') =
125 foreach(h', fn e => (insert(h, Elt.key e, Elt.value e); ()))
126
127end