forked from functionaljava/functionaljava
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPriorityQueue.java
More file actions
224 lines (194 loc) · 6.39 KB
/
PriorityQueue.java
File metadata and controls
224 lines (194 loc) · 6.39 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
package fj.data;
import fj.Equal;
import fj.F;
import fj.F2;
import fj.Monoid;
import fj.Ord;
import fj.P;
import fj.P2;
import fj.Show;
import fj.data.fingertrees.FingerTree;
import static fj.Function.compose;
import static fj.data.Option.none;
import static fj.data.Option.some;
/**
* A priority queue implementation backed by a
* {@link fj.data.fingertrees.FingerTree}. The finger tree nodes are
* annotated with type K, are combined using a monoid of K and both the
* key and value are stored in the leaf. Priorities of the same value
* are returned FIFO (first in, first out).
*
* Created by MarkPerry on 31 May 16.
*/
public final class PriorityQueue<K, A> {
private final FingerTree<K, P2<K, A>> ftree;
private final Equal<K> equal;
private PriorityQueue(Equal<K> e, FingerTree<K, P2<K, A>> ft) {
equal = e;
ftree = ft;
}
/**
* Creates a priority queue from a finger tree.
*/
public static <K, A> PriorityQueue<K, A> priorityQueue(Equal<K> e, FingerTree<K, P2<K, A>> ft) {
return new PriorityQueue<>(e, ft);
}
/**
* Creates an empty priority queue.
*
* @param m A monoid to combine node annotations.
* @param e A value to compare key equality.
*/
public static <K, A> PriorityQueue<K, A> empty(Monoid<K> m, Equal<K> e) {
return priorityQueue(e, FingerTree.empty(m, P2.__1()));
}
/**
* An empty priority queue with integer priorities.
*/
public static <A> PriorityQueue<Integer, A> emptyInt() {
return empty(Monoid.intMaxMonoid, Equal.intEqual);
}
/**
* Maps the values in each node with function f.
*/
public <B> PriorityQueue<K, B> map(F<A, B> f) {
return priorityQueue(equal,
ftree.map(P2.map2_(f),
FingerTree.measured(ftree.measured().monoid(), P2.__1())
)
);
}
/**
* Filters nodes based on the value inside each node.
*/
public PriorityQueue<K, A> filterValues(F<A, Boolean> f) {
return priorityQueue(equal, ftree.filter(p2 -> f.f(p2._2())));
}
/**
* Filters the nodes based on the annotation of each node.
*/
public PriorityQueue<K, A> filterKeys(F<K, Boolean> f) {
return priorityQueue(equal, ftree.filter(p2 -> f.f(p2._1())));
}
/**
* Is the tree empty?
*/
public boolean isEmpty() {
return ftree.isEmpty();
}
/**
* If the tree is not empty, returns the node with highest priority otherwise returns nothing.
*/
public Option<P2<K, A>> top() {
return unqueue(none(), (top, tail) -> some(top));
}
/**
* Returns all the elements of the queue with the highest (same) priority.
*/
public List<P2<K, A>> topN() {
return toStream().uncons(
List.nil(),
top -> tail -> List.cons(top, tail._1().takeWhile(compose(equal.eq(top._1()), P2.__1())).toList())
);
}
/**
* Adds a node with priority k and value a. This operation take O(1).
*/
public PriorityQueue<K, A> enqueue(K k, A a) {
return priorityQueue(equal, ftree.snoc(P.p(k, a)));
}
/**
* Adds nodes using the list of products with priority k and value a. This operation takes O(list.length()).
*/
public PriorityQueue<K, A> enqueue(List<P2<K, A>> list) {
return list.foldLeft((pq, p) -> pq.enqueue(p._1(), p._2()), this);
}
/**
* Does the priority k exist already?
*/
public boolean contains(final K k) {
return !ftree.split(equal.eq(k))._2().isEmpty();
}
/**
* Adds nodes using the iterable of products with priority k and value a.
*/
public PriorityQueue<K, A> enqueue(Iterable<P2<K, A>> it) {
PriorityQueue<K, A> result = this;
for (P2<K, A> p: it) {
result = result.enqueue(p);
}
return result;
}
/**
* Adds a node with priority k and value a. This operation take O(1).
*/
public PriorityQueue<K, A> enqueue(P2<K, A> p) {
return enqueue(p._1(), p._2());
}
/**
* Removes the node with the highest priority.
*/
public PriorityQueue<K, A> dequeue() {
return unqueue(this, (top, tail) -> tail);
}
/**
* Returns a tuple of the node with the highest priority and the rest of the priority queue.
*/
public P2<Option<P2<K, A>>, PriorityQueue<K, A>> topDequeue() {
return unqueue(P.p(none(), this), (top, tail) -> P.p(some(top), tail));
}
/**
* Performs a reduction on this priority queue using the given arguments.
*
* @param empty The value to return if this queue is empty.
* @param topDequeue The function to apply to the top priority element and the tail of the queue (without its top element).
* @return A reduction on this queue.
*/
public <B> B unqueue(B empty, F2<P2<K, A>, PriorityQueue<K, A>, B> topDequeue) {
K top = ftree.measure();
P2<FingerTree<K, P2<K, A>>, FingerTree<K, P2<K, A>>> p = ftree.split(equal.eq(top));
return p._2().uncons(
empty,
(head, tail) -> topDequeue.f(head, priorityQueue(equal, p._1().append(tail)))
);
}
/**
* Removes the top n elements with the highest priority.
*/
public PriorityQueue<K, A> dequeue(int n) {
int i = n;
PriorityQueue<K, A> result = this;
while (i > 0) {
i--;
result = result.dequeue();
}
return result;
}
/**
* Does the top of the queue have lower priority than k?
*/
public boolean isLessThan(Ord<K> ok, K k) {
return top().option(true, p -> ok.isLessThan(p._1(), k));
}
public boolean isGreaterThan(Ord<K> ok, K k) {
return top().option(false, p -> ok.isGreaterThan(p._1(), k));
}
public boolean isEqual(Ord<K> ok, K k) {
return top().option(false, p -> ok.eq(p._1(), k));
}
/**
* Returns a stream of products with priority k and value a.
*/
public Stream<P2<K, A>> toStream() {
return unqueue(Stream.nil(), (top, tail) -> Stream.cons(top, () -> tail.toStream()));
}
/**
* Returns a list of products with priority k and value a.
*/
public List<P2<K, A>> toList() {
return toStream().toList();
}
public String toString() {
return Show.priorityQueueShow(Show.<K>anyShow(), Show.<A>anyShow()).showS(this);
}
}