Libraryless. Click here for Pure Java version (3263L/20K).
1 | // based on: https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html |
2 | sclass LongTreeSet extends AbstractSet<Long> { |
3 | // Left-leaning red-black BST with long values. |
4 | // This is the 2-3 version. |
5 | |
6 | private static final boolean RED = true; |
7 | private static final boolean BLACK = false; |
8 | |
9 | private Node root; // root of the BST |
10 | int size; // size of tree set |
11 | |
12 | // BST helper node data type |
13 | private sclass Node { |
14 | private long val; // associated data |
15 | private Node left, right; // links to left and right subtrees |
16 | private bool color; // color of parent link |
17 | |
18 | public Node(long val, boolean color) { |
19 | this.val = val; |
20 | this.color = color; |
21 | } |
22 | } |
23 | |
24 | *() {} |
25 | *(Cl<Long> cl) { addAll(cl); } |
26 | |
27 | // is node x red; false if x is null ? |
28 | private boolean isRed(Node x) { |
29 | if (x == null) return false; |
30 | return x.color == RED; |
31 | } |
32 | |
33 | public int size() { |
34 | ret size; |
35 | } |
36 | |
37 | public bool isEmpty() { |
38 | return root == null; |
39 | } |
40 | |
41 | @Override public bool add(Long val) { ret add((long) val); } |
42 | public bool add(long val) { |
43 | int oldSize = size; |
44 | root = put(root, val); |
45 | root.color = BLACK; |
46 | ifdef CompactTreeSet_debug assertTrue(check()); endifdef |
47 | ret size > oldSize; |
48 | } |
49 | |
50 | // insert the value in the subtree rooted at h |
51 | private Node put(Node h, long val) { |
52 | if (h == null) { ++size; ret new Node(val, RED); } |
53 | |
54 | int cmp = compare(val, h.val); |
55 | if (cmp < 0) h.left = put(h.left, val); |
56 | else if (cmp > 0) h.right = put(h.right, val); |
57 | else { /*h.val = val;*/ } // no overwriting |
58 | |
59 | // fix-up any right-leaning links |
60 | if (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h); |
61 | if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); |
62 | if (isRed(h.left) && isRed(h.right)) flipColors(h); |
63 | |
64 | ret h; |
65 | } |
66 | |
67 | // override if you want custom sorting |
68 | int compare(long a, long b) { |
69 | ret cmp(a, b); |
70 | } |
71 | |
72 | @Override public bool remove(O key) { ret remove((long) key); } |
73 | public bool remove(long key) { |
74 | if (!contains(key)) false; |
75 | |
76 | // if both children of root are black, set root to red |
77 | if (!isRed(root.left) && !isRed(root.right)) |
78 | root.color = RED; |
79 | |
80 | root = delete(root, key); |
81 | if (!isEmpty()) root.color = BLACK; |
82 | // assert check(); |
83 | true; |
84 | } |
85 | |
86 | // delete the key-value pair with the given key rooted at h |
87 | private Node delete(Node h, long key) { |
88 | // assert get(h, key) != null; |
89 | |
90 | if (compare(key, h.val) < 0) { |
91 | if (!isRed(h.left) && !isRed(h.left.left)) |
92 | h = moveRedLeft(h); |
93 | h.left = delete(h.left, key); |
94 | } |
95 | else { |
96 | if (isRed(h.left)) |
97 | h = rotateRight(h); |
98 | if (compare(key, h.val) == 0 && (h.right == null)) { |
99 | --size; null; |
100 | } if (!isRed(h.right) && !isRed(h.right.left)) |
101 | h = moveRedRight(h); |
102 | if (compare(key, h.val) == 0) { |
103 | --size; |
104 | Node x = min(h.right); |
105 | h.val = x.val; |
106 | // h.val = get(h.right, min(h.right).val); |
107 | // h.val = min(h.right).val; |
108 | h.right = deleteMin(h.right); |
109 | } |
110 | else h.right = delete(h.right, key); |
111 | } |
112 | return balance(h); |
113 | } |
114 | |
115 | // make a left-leaning link lean to the right |
116 | private Node rotateRight(Node h) { |
117 | // assert (h != null) && isRed(h.left); |
118 | Node x = h.left; |
119 | h.left = x.right; |
120 | x.right = h; |
121 | x.color = x.right.color; |
122 | x.right.color = RED; |
123 | return x; |
124 | } |
125 | |
126 | // make a right-leaning link lean to the left |
127 | private Node rotateLeft(Node h) { |
128 | // assert (h != null) && isRed(h.right); |
129 | Node x = h.right; |
130 | h.right = x.left; |
131 | x.left = h; |
132 | x.color = x.left.color; |
133 | x.left.color = RED; |
134 | return x; |
135 | } |
136 | |
137 | // flip the colors of a node and its two children |
138 | private void flipColors(Node h) { |
139 | // h must have opposite color of its two children |
140 | // assert (h != null) && (h.left != null) && (h.right != null); |
141 | // assert (!isRed(h) && isRed(h.left) && isRed(h.right)) |
142 | // || (isRed(h) && !isRed(h.left) && !isRed(h.right)); |
143 | h.color = !h.color; |
144 | h.left.color = !h.left.color; |
145 | h.right.color = !h.right.color; |
146 | } |
147 | |
148 | // Assuming that h is red and both h.left and h.left.left |
149 | // are black, make h.left or one of its children red. |
150 | private Node moveRedLeft(Node h) { |
151 | // assert (h != null); |
152 | // assert isRed(h) && !isRed(h.left) && !isRed(h.left.left); |
153 | |
154 | flipColors(h); |
155 | if (isRed(h.right.left)) { |
156 | h.right = rotateRight(h.right); |
157 | h = rotateLeft(h); |
158 | flipColors(h); |
159 | } |
160 | return h; |
161 | } |
162 | |
163 | // Assuming that h is red and both h.right and h.right.left |
164 | // are black, make h.right or one of its children red. |
165 | private Node moveRedRight(Node h) { |
166 | // assert (h != null); |
167 | // assert isRed(h) && !isRed(h.right) && !isRed(h.right.left); |
168 | flipColors(h); |
169 | if (isRed(h.left.left)) { |
170 | h = rotateRight(h); |
171 | flipColors(h); |
172 | } |
173 | return h; |
174 | } |
175 | |
176 | // restore red-black tree invariant |
177 | private Node balance(Node h) { |
178 | // assert (h != null); |
179 | |
180 | if (isRed(h.right)) h = rotateLeft(h); |
181 | if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h); |
182 | if (isRed(h.left) && isRed(h.right)) flipColors(h); |
183 | |
184 | return h; |
185 | } |
186 | |
187 | |
188 | /** |
189 | * Returns the height of the BST (for debugging). |
190 | * @return the height of the BST (a 1-node tree has height 0) |
191 | */ |
192 | public int height() { |
193 | return height(root); |
194 | } |
195 | |
196 | private int height(Node x) { |
197 | if (x == null) return -1; |
198 | return 1 + Math.max(height(x.left), height(x.right)); |
199 | } |
200 | |
201 | @Override public bool contains(O val) { ret contains((long) val); } |
202 | public bool contains(long val) { |
203 | ret find(root, val) != null; |
204 | } |
205 | |
206 | Node find(Node x, long key) { |
207 | while (x != null) { |
208 | int cmp = compare(key, x.val); |
209 | if (cmp < 0) x = x.left; |
210 | else if (cmp > 0) x = x.right; |
211 | else ret x; |
212 | } |
213 | null; |
214 | } |
215 | |
216 | private boolean check() { |
217 | if (!is23()) println("Not a 2-3 tree"); |
218 | if (!isBalanced()) println("Not balanced"); |
219 | return is23() && isBalanced(); |
220 | } |
221 | |
222 | // Does the tree have no red right links, and at most one (left) |
223 | // red links in a row on any path? |
224 | private boolean is23() { return is23(root); } |
225 | private boolean is23(Node x) { |
226 | if (x == null) return true; |
227 | if (isRed(x.right)) return false; |
228 | if (x != root && isRed(x) && isRed(x.left)) |
229 | return false; |
230 | return is23(x.left) && is23(x.right); |
231 | } |
232 | |
233 | // do all paths from root to leaf have same number of black edges? |
234 | private boolean isBalanced() { |
235 | int black = 0; // number of black links on path from root to min |
236 | Node x = root; |
237 | while (x != null) { |
238 | if (!isRed(x)) black++; |
239 | x = x.left; |
240 | } |
241 | return isBalanced(root, black); |
242 | } |
243 | |
244 | // does every path from the root to a leaf have the given number of black links? |
245 | private boolean isBalanced(Node x, int black) { |
246 | if (x == null) return black == 0; |
247 | if (!isRed(x)) black--; |
248 | return isBalanced(x.left, black) && isBalanced(x.right, black); |
249 | } |
250 | |
251 | public void clear() { root = null; size = 0; } |
252 | |
253 | // the smallest key in subtree rooted at x; null if no such key |
254 | private Node min(Node x) { |
255 | // assert x != null; |
256 | while (x.left != null) x = x.left; |
257 | ret x; |
258 | } |
259 | |
260 | private Node deleteMin(Node h) { |
261 | if (h.left == null) |
262 | return null; |
263 | |
264 | if (!isRed(h.left) && !isRed(h.left.left)) |
265 | h = moveRedLeft(h); |
266 | |
267 | h.left = deleteMin(h.left); |
268 | ret balance(h); |
269 | } |
270 | |
271 | public Iterator<Long> iterator() { |
272 | ret new MyIterator; |
273 | } |
274 | |
275 | class MyIterator extends ItIt<Long> { |
276 | new L<Node> path; |
277 | |
278 | *() { |
279 | fetch(root); |
280 | } |
281 | |
282 | void fetch(Node node) { |
283 | while (node != null) { |
284 | path.add(node); |
285 | node = node.left; |
286 | } |
287 | } |
288 | |
289 | public bool hasNext() { ret !path.isEmpty(); } |
290 | |
291 | public Long next() { |
292 | if (path.isEmpty()) fail("no more elements"); |
293 | Node node = popLast(path); |
294 | // last node is always a leaf, so left is null |
295 | // so proceed to fetch right branch |
296 | fetch(node.right); |
297 | ret node.val; |
298 | } |
299 | } |
300 | |
301 | // Returns the smallest key in the symbol table greater than or equal to {@code key}. |
302 | public Long ceiling(long key) { |
303 | Node x = ceiling(root, key); |
304 | ret x == null ? null : x.val; |
305 | } |
306 | |
307 | // the smallest key in the subtree rooted at x greater than or equal to the given key |
308 | Node ceiling(Node x, long key) { |
309 | if (x == null) null; |
310 | int cmp = compare(key, x.val); |
311 | if (cmp == 0) ret x; |
312 | if (cmp > 0) ret ceiling(x.right, key); |
313 | Node t = ceiling(x.left, key); |
314 | if (t != null) ret t; |
315 | else ret x; |
316 | } |
317 | |
318 | public Long floor(long key) { |
319 | Node x = floor(root, key); |
320 | ret x == null ? null : x.val; |
321 | } |
322 | |
323 | // the largest key in the subtree rooted at x less than or equal to the given key |
324 | Node floor(Node x, long key) { |
325 | if (x == null) null; |
326 | int cmp = compare(key, x.val); |
327 | if (cmp == 0) ret x; |
328 | if (cmp < 0) ret floor(x.left, key); |
329 | Node t = floor(x.right, key); |
330 | if (t != null) ret t; |
331 | else ret x; |
332 | } |
333 | } |
Began life as a copy of #1029166
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt
No comments. add comment
Snippet ID: | #1030399 |
Snippet name: | LongTreeSet [apparently OK] |
Eternal ID of this version: | #1030399/14 |
Text MD5: | 81c72263b7b60a6ae4931918858dc77a |
Transpilation MD5: | 988c5ffcfaf2b5c02e849df0c4c36ab7 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2020-12-13 17:23:45 |
Source code size: | 9555 bytes / 333 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 252 / 523 |
Version history: | 13 change(s) |
Referenced in: | [show references] |