-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy pathPriorityQueue.fs
More file actions
408 lines (315 loc) · 14 KB
/
Copy pathPriorityQueue.fs
File metadata and controls
408 lines (315 loc) · 14 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
// based on pairing heap published by Okasaki
// original implementation taken from http://lepensemoi.free.fr/index.php/2009/12/17/pairing-heap
//J.F. modified
namespace FSharpx.Collections
type IPriorityQueue<'T when 'T: comparison> =
inherit System.Collections.IEnumerable
inherit System.Collections.Generic.IEnumerable<'T>
inherit System.Collections.Generic.IReadOnlyCollection<'T>
abstract member IsEmpty: bool
///returns a new queue with the element added to the end
abstract member Insert: 'T -> IPriorityQueue<'T>
///returns option first element
abstract member TryPeek: unit -> 'T option
///returns the first element
abstract member Peek: unit -> 'T
///returns the count of the elements
abstract member Length: int
//returns the option first element and tail
abstract member TryPop: unit -> ('T * IPriorityQueue<'T>) option
///returns the first element and tail
abstract member Pop: unit -> 'T * IPriorityQueue<'T>
open System.Collections
open System.Collections.Generic
/// Heap is an ordered linear structure where the ordering is either ascending or descending.
/// "head" inspects the first element in the ordering, "tail" takes the remaining structure
/// after head, and "insert" places elements within the ordering. PriorityQueue is available
/// as an alternate interface.
/// According to Okasaki the time complexity of the heap functions in this Heap implementation
/// (based on the "pairing" heap) have "resisted" time complexity analysis.
type Heap<'T when 'T: comparison>(isDescending: bool, length: int, data: HeapData<'T>) =
let mutable hashCode = None
member internal this.heapData = data
member internal this.heapLength = length
override this.GetHashCode() =
match hashCode with
| None ->
let mutable hash = 1
for x in this do
hash <- 31 * hash + Unchecked.hash x
hashCode <- Some hash
hash
| Some hash -> hash
override this.Equals(other) =
match other with
| :? Heap<'T> as y -> (this :> System.IEquatable<Heap<'T>>).Equals(y)
| _ -> false
static member private merge isDescending newLength (h1: HeapData<'T>) (h2: HeapData<'T>) : Heap<'T> =
match h1, h2 with
| E, h -> Heap(isDescending, newLength, h)
| h, E -> Heap(isDescending, newLength, h)
| T(x, xs), T(y, ys) ->
if isDescending then
if x <= y then
Heap(isDescending, newLength, T(y, h1 :: ys))
else
Heap(isDescending, newLength, T(x, h2 :: xs))
else if x <= y then
Heap(isDescending, newLength, T(x, h2 :: xs))
else
Heap(isDescending, newLength, T(y, h1 :: ys))
//http://lorgonblog.wordpress.com/2008/04/06/catamorphisms-part-two
static member private foldHeap nodeF leafV (h: list<HeapData<'T>>) =
let rec loop (h: list<HeapData<'T>>) cont =
match h with
| T(a, h') :: tl -> loop h' (fun lacc -> loop tl (fun racc -> cont(nodeF a lacc racc)))
| _ -> cont leafV
loop h (fun x -> x)
static member private inOrder(h: list<HeapData<'T>>) =
(Heap.foldHeap (fun x l r acc -> l(x :: (r acc))) (fun acc -> acc) h) []
static member internal ofSeq (isDescending: bool) (s: seq<'T>) : Heap<'T> =
if Seq.isEmpty s then
Heap(isDescending, 0, E)
else
let len, h' =
Seq.fold
(fun (lnth, (h: 'T HeapData)) x ->
match h with
| E -> 1, T(x, [])
| T(y, ys) ->
if isDescending then
if x <= y then
(lnth + 1), T(y, T(x, []) :: ys)
else
(lnth + 1), T(x, T(y, ys) :: [])
else if x <= y then
(lnth + 1), T(x, T(y, ys) :: [])
else
(lnth + 1), T(y, T(x, []) :: ys))
(0, E)
s
Heap(isDescending, len, h')
///O(1) worst case. Returns the min or max element.
member this.Head =
match data with
| E -> raise(new System.Exception("Heap is empty"))
| T(x, _) -> x
///O(1) worst case. Returns option first min or max element.
member this.TryHead =
match data with
| E -> None
| T(x, _) -> Some(x)
///O(log n) amortized time. Returns a new heap with the element inserted.
member this.Insert x =
Heap.merge isDescending (length + 1) (T(x, [])) data
///O(1). Returns true if the heap has no elements.
member this.IsEmpty =
match data with
| E -> true
| _ -> false
///O(1). Returns true if the heap has max element at head.
member this.IsDescending = isDescending
///O(1). Returns the count of elememts.
member this.Length = length
///O(log n) amortized time. Returns heap from merging two heaps, both must have same descending.
member this.Merge(xs: Heap<'T>) =
if isDescending = xs.IsDescending then
Heap.merge isDescending (length + xs.heapLength) data xs.heapData
else
failwith "heaps to merge have different sort orders"
///O(log n) amortized time. Returns heap option from merging two heaps.
member this.TryMerge(xs: Heap<'T>) =
if isDescending = xs.IsDescending then
Some(Heap.merge isDescending (length + xs.heapLength) data xs.heapData)
else
None
///O(n log n). Returns heap reversed.
member this.Rev() =
if isDescending then
Heap<'T>.ofSeq false (this :> seq<'T>)
else
Heap<'T>.ofSeq true (this :> seq<'T>)
///O(log n) amortized time. Returns a new heap of the elements trailing the head.
member this.Tail() =
let mergeData (h1: HeapData<'T>) (h2: HeapData<'T>) : HeapData<'T> =
match h1, h2 with
| E, h -> h
| h, E -> h
| T(x, xs), T(y, ys) ->
if isDescending then
if x <= y then T(y, h1 :: ys) else T(x, h2 :: xs)
else if x <= y then
T(x, h2 :: xs)
else
T(y, h1 :: ys)
match data with
| E -> raise(new System.Exception("Heap is empty"))
| T(x, xs) ->
let combinePairs state item =
match state with
| Some p, l -> (None, (mergeData item p) :: l)
| None, l -> (Some item, l)
let tail =
xs
|> List.fold combinePairs (None, [])
|> function
| Some i, l -> i :: l
| None, l -> l
|> List.fold mergeData E
Heap(isDescending, (length - 1), tail)
///O(log n) amortized time. Returns option heap of the elements trailing the head.
member this.TryTail() =
match data with
| E -> None
| _ -> Some(this.Tail())
///O(log n) amortized time. Returns the head element and tail.
member this.Uncons() =
match data with
| E -> raise(new System.Exception("Heap is empty"))
| T(x, xs) -> x, this.Tail()
///O(log n) amortized time. Returns option head element and tail.
member this.TryUncons() =
match data with
| E -> None
| T(x, xs) -> Some(x, this.Tail())
interface System.IEquatable<Heap<'T>> with
member this.Equals(y: Heap<'T>) =
if this.Length <> y.Length then false
else if this.GetHashCode() <> y.GetHashCode() then false
else Seq.forall2 (Unchecked.equals) this y
interface IEnumerable<'T> with
member this.GetEnumerator() =
let e =
let listH = data :: []
if isDescending then
Heap.inOrder listH |> List.sort |> List.rev |> List.toSeq
else
Heap.inOrder listH |> List.sort |> List.toSeq
e.GetEnumerator()
interface IEnumerable with
member this.GetEnumerator() =
(this :> _ seq).GetEnumerator() :> IEnumerator
interface IPriorityQueue<'T> with
member this.IsEmpty = this.IsEmpty
member this.Insert element =
this.Insert element :> IPriorityQueue<'T>
member this.TryPeek() =
this.TryHead
member this.Peek() = this.Head
member this.Length = this.Length
member this.Count = this.Length
member this.TryPop() =
match this.TryUncons() with
| Some(element, newHeap) -> Some(element, newHeap :> IPriorityQueue<'T>)
| None -> None
member this.Pop() =
let element, newHeap = this.Uncons()
element, (newHeap :> IPriorityQueue<'T>)
and HeapData<'T when 'T: comparison> =
| E
| T of 'T * list<HeapData<'T>>
[<RequireQualifiedAccess>]
module Heap =
//pattern discriminator
let (|Cons|Nil|)(h: Heap<'T>) =
match h.TryUncons() with
| Some(a, b) -> Cons(a, b)
| None -> Nil
///O(1). Returns a empty heap.
let empty<'T when 'T: comparison>(isDescending: bool) =
Heap<'T>(isDescending, 0, E)
///O(1) worst case. Returns the min or max element.
let inline head(xs: Heap<'T>) = xs.Head
///O(1) worst case. Returns option first min or max element.
let inline tryHead(xs: Heap<'T>) =
xs.TryHead
///O(log n) amortized time. Returns a new heap with the element inserted.
let inline insert x (xs: Heap<'T>) =
xs.Insert x
///O(1). Returns true if the heap has no elements.
let inline isEmpty(xs: Heap<'T>) =
xs.IsEmpty
///O(1). Returns true if the heap has max element at head.
let inline isDescending(xs: Heap<'T>) =
xs.IsDescending
///O(n). Returns the count of elememts.
let inline length(xs: Heap<'T>) = xs.Length
///O(log n) amortized time. Returns heap from merging two heaps, both must have same descending.
let inline merge (xs: Heap<'T>) (ys: Heap<'T>) =
xs.Merge ys
///O(log n) amortized time. Returns heap option from merging two heaps.
let inline tryMerge (xs: Heap<'T>) (ys: Heap<'T>) =
xs.TryMerge ys
///O(n log n). Returns heap, bool isDescending, from the sequence.
let ofSeq isDescending s =
Heap<'T>.ofSeq isDescending s
///O(n). Returns heap reversed.
let inline rev(xs: Heap<'T>) = xs.Rev()
///O(log n) amortized time. Returns a new heap of the elements trailing the head.
let inline tail(xs: Heap<'T>) = xs.Tail()
///O(log n) amortized time. Returns option heap of the elements trailing the head.
let inline tryTail(xs: Heap<'T>) =
xs.TryTail()
///O(n). Views the given heap as a sequence.
let inline toSeq(xs: Heap<'T>) =
xs :> seq<'T>
///O(log n) amortized time. Returns the head element and tail.
let inline uncons(xs: Heap<'T>) =
xs.Uncons()
///O(log n) amortized time. Returns option head element and tail.
let inline tryUncons(xs: Heap<'T>) =
xs.TryUncons()
///O(n). Returns a sorted list of all elements.
let inline toList(xs: Heap<'T>) =
xs |> toSeq |> Seq.toList
///O(n). Returns a sorted array of all elements.
let inline toArray(xs: Heap<'T>) =
xs |> toSeq |> Seq.toArray
///O(n log n). Returns heap from a list.
let inline ofList isDescending (xs: 'T list) =
ofSeq isDescending xs
///O(n log n). Returns heap from an array.
let inline ofArray isDescending (xs: 'T array) =
ofSeq isDescending xs
///O(n). Applies a function to each element in sorted order, threading an accumulator.
let inline fold (f: 'State -> 'T -> 'State) (state: 'State) (xs: Heap<'T>) =
xs |> toSeq |> Seq.fold f state
///O(n). Applies a function to each element in sorted order.
let inline iter (f: 'T -> unit) (xs: Heap<'T>) =
xs |> toSeq |> Seq.iter f
///O(n). Returns true if any element satisfies the predicate.
let inline exists (f: 'T -> bool) (xs: Heap<'T>) =
xs |> toSeq |> Seq.exists f
///O(n). Returns true if all elements satisfy the predicate.
let inline forall (f: 'T -> bool) (xs: Heap<'T>) =
xs |> toSeq |> Seq.forall f
///O(n log n). Returns a new heap with elements mapped by the function, preserving sort direction.
let inline map (f: 'T -> 'U) (xs: Heap<'T>) : Heap<'U> =
xs |> toSeq |> Seq.map f |> ofSeq(isDescending xs)
///O(n log n). Returns a new heap containing only elements satisfying the predicate.
let inline filter (f: 'T -> bool) (xs: Heap<'T>) =
xs |> toSeq |> Seq.filter f |> ofSeq(isDescending xs)
///O(n log n). Applies an option-returning function to each element; returns a new heap of the Some values.
let inline choose (f: 'T -> 'U option) (xs: Heap<'T>) : Heap<'U> =
xs |> toSeq |> Seq.choose f |> ofSeq(isDescending xs)
[<RequireQualifiedAccess>]
module PriorityQueue =
///O(1). Returns a empty queue, with indicated ordering.
let empty<'T when 'T: comparison> isDescending =
Heap.empty isDescending :> IPriorityQueue<'T>
///O(1). Returns true if the queue has no elements.
let inline isEmpty(pq: IPriorityQueue<'T>) =
pq.IsEmpty
///O(log n) amortized time. Returns a new queue with the element added to the end.
let inline insert element (pq: IPriorityQueue<'T>) =
pq.Insert element
///O(1). Returns option first element.
let inline tryPeek(pq: IPriorityQueue<'T>) =
pq.TryPeek()
///O(1). Returns the first element.
let inline peek(pq: IPriorityQueue<'T>) = pq.Peek()
///O(log n) amortized time. Returns the option first element and tail.
let inline tryPop(pq: IPriorityQueue<'T>) =
pq.TryPop()
///O(log n) amortized time. Returns the first element and tail.
let inline pop(pq: IPriorityQueue<'T>) = pq.Pop()