Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

361
LINES

< > BotCompany Repo | #1030938 // UltraCompactTreeSet [seems to work. 24 bytes per entry as opposed to 40 bytes in TreeSet]

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (3303L/20K).

1  
// based on: https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
2  
// TODO: implement NavigableSet
3  
sclass UltraCompactTreeSet<A> extends AbstractSet<A> {
4  
5  
  // A symbol table implemented using a left-leaning red-black BST.
6  
  // This is the 2-3 version.
7  
 
8  
  private static final boolean RED   = true;
9  
  private static final boolean BLACK = false;
10  
11  
  private Node<A> root;     // root of the BST
12  
  int size; // size of tree set
13  
14  
  // BST helper node data type
15  
  abstract sclass Node<A> {
16  
    A val;         // associated data
17  
    Node<A> left, right;  // links to left and right subtrees
18  
19  
    abstract bool color();
20  
    abstract BlackNode<A> convertToBlack();
21  
    abstract RedNode<A> convertToRed();
22  
    abstract Node<A> invertColor();
23  
    Node<A> convertToColor(bool color) { ret color == RED ? convertToRed() : convertToBlack(); }
24  
  }
25  
26  
  sclass BlackNode<A> extends Node<A> {
27  
    *(A *val) {}
28  
    *(A *val, Node<A> *left, Node<A> *right) {}
29  
    
30  
    bool color() { ret BLACK; }
31  
    BlackNode<A> convertToBlack() { this; }
32  
    RedNode<A> convertToRed() { ret new RedNode(val, left, right); }
33  
    Node invertColor() { ret convertToRed(); }
34  
  }
35  
36  
  sclass RedNode<A> extends Node<A> {
37  
    *(A *val) {}
38  
    *(A *val, Node<A> *left, Node<A> *right) {}
39  
40  
    bool color() { ret RED; }
41  
    BlackNode<A> convertToBlack() { ret new BlackNode(val, left, right); }
42  
    RedNode<A> convertToRed() { this; }
43  
    Node invertColor() { ret convertToBlack(); }
44  
  }
45  
  
46  
  *() {}
47  
  *(Cl<? extends A> cl) { addAll(cl); }
48  
49  
  // is node x red; false if x is null ?
50  
  static bool <A> isRed(Node<A> x) {
51  
    ret x instanceof RedNode;
52  
  }
53  
54  
  public int size() {
55  
    ret size;
56  
  }
57  
58  
  public bool isEmpty() {
59  
    ret root == null;
60  
  }
61  
62  
  public bool add(A val) {
63  
    int oldSize = size;
64  
    root = put(root, val);
65  
    root = root.convertToBlack();
66  
    ifdef CompactTreeSet_debug assertTrue(check()); endifdef
67  
    ret size > oldSize;
68  
  }
69  
70  
  // insert the value in the subtree rooted at h
71  
  private Node<A> put(Node<A> h, A val) { 
72  
    if (h == null) { ++size; ret new RedNode(val); }
73  
74  
    int cmp = compare(val, h.val);
75  
    if      (cmp < 0) h.left  = put(h.left,  val); 
76  
    else if (cmp > 0) h.right = put(h.right, val); 
77  
    else              { /*h.val = val;*/ } // no overwriting
78  
79  
    // fix-up any right-leaning links
80  
    if (isRed(h.right) && !isRed(h.left))      h = rotateLeft(h);
81  
    if (isRed(h.left)  &&  isRed(h.left.left)) h = rotateRight(h);
82  
    if (isRed(h.left)  &&  isRed(h.right))     h = flipColors(h);
83  
84  
    ret h;
85  
  }
86  
  
87  
  // override me if you wish
88  
  int compare(A a, A b) {
89  
    ret cmp(a, b);
90  
  }
91  
92  
  public bool remove(O key) { 
93  
    if (!contains(key)) false;
94  
95  
    // if both children of root are black, set root to red
96  
    if (!isRed(root.left) && !isRed(root.right))
97  
        root = root.convertToRed();
98  
99  
    root = delete(root, (A) key);
100  
    if (!isEmpty()) root = root.convertToBlack();
101  
    // assert check();
102  
    true;
103  
  }
104  
105  
  // delete the key-value pair with the given key rooted at h
106  
  private Node delete(Node<A> h, A key) { 
107  
    // assert get(h, key) != null;
108  
109  
    if (compare(key, h.val) < 0)  {
110  
      if (!isRed(h.left) && !isRed(h.left.left))
111  
          h = moveRedLeft(h);
112  
      h.left = delete(h.left, key);
113  
    }
114  
    else {
115  
      if (isRed(h.left))
116  
          h = rotateRight(h);
117  
      if (compare(key, h.val) == 0 && (h.right == null)) {
118  
          --size; null;
119  
      } if (!isRed(h.right) && !isRed(h.right.left))
120  
          h = moveRedRight(h);
121  
      if (compare(key, h.val) == 0) {
122  
          --size;
123  
          Node<A> x = min(h.right);
124  
          h.val = x.val;
125  
          // h.val = get(h.right, min(h.right).val);
126  
          // h.val = min(h.right).val;
127  
          h.right = deleteMin(h.right);
128  
      }
129  
      else h.right = delete(h.right, key);
130  
    }
131  
    return balance(h);
132  
  }
133  
134  
  // make a left-leaning link lean to the right
135  
  private Node<A> rotateRight(Node<A> h) {
136  
      // assert (h != null) && isRed(h.left);
137  
      Node<A> x = h.left;
138  
      h.left = x.right;
139  
      x.right = h;
140  
      x = x.convertToColor(x.right.color());
141  
      x.right = x.right.convertToRed();
142  
      ret x;
143  
  }
144  
145  
  // make a right-leaning link lean to the left
146  
  private Node<A> rotateLeft(Node<A> h) {
147  
      // assert (h != null) && isRed(h.right);
148  
      Node<A> x = h.right;
149  
      h.right = x.left;
150  
      x.left = h;
151  
      x = x.convertToColor(x.left.color());
152  
      x.left = x.left.convertToRed();
153  
      ret x;
154  
  }
155  
156  
  // flip the colors of a node and its two children
157  
  private Node<A> flipColors(Node<A> h) {
158  
      // h must have opposite color of its two children
159  
      // assert (h != null) && (h.left != null) && (h.right != null);
160  
      // assert (!isRed(h) &&  isRed(h.left) &&  isRed(h.right))
161  
      //    || (isRed(h)  && !isRed(h.left) && !isRed(h.right));
162  
      h.left = h.left.invertColor();
163  
      h.right = h.right.invertColor();
164  
      ret h.invertColor();
165  
  }
166  
167  
  // Assuming that h is red and both h.left and h.left.left
168  
  // are black, make h.left or one of its children red.
169  
  private Node<A> moveRedLeft(Node<A> h) {
170  
      // assert (h != null);
171  
      // assert isRed(h) && !isRed(h.left) && !isRed(h.left.left);
172  
173  
      h = flipColors(h);
174  
      if (isRed(h.right.left)) { 
175  
          h.right = rotateRight(h.right);
176  
          h = rotateLeft(h);
177  
          h = flipColors(h);
178  
      }
179  
      ret h;
180  
  }
181  
182  
  // Assuming that h is red and both h.right and h.right.left
183  
  // are black, make h.right or one of its children red.
184  
  private Node<A> moveRedRight(Node<A> h) {
185  
      // assert (h != null);
186  
      // assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);
187  
      h = flipColors(h);
188  
      if (isRed(h.left.left)) { 
189  
          h = rotateRight(h);
190  
          h = flipColors(h);
191  
      }
192  
      ret h;
193  
  }
194  
195  
  // restore red-black tree invariant
196  
  private Node<A> balance(Node<A> h) {
197  
      // assert (h != null);
198  
199  
      if (isRed(h.right))                      h = rotateLeft(h);
200  
      if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
201  
      if (isRed(h.left) && isRed(h.right))     h = flipColors(h);
202  
203  
      ret h;
204  
  }
205  
206  
207  
  /**
208  
   * Returns the height of the BST (for debugging).
209  
   * @return the height of the BST (a 1-node tree has height 0)
210  
   */
211  
  public int height() {
212  
      ret height(root);
213  
  }
214  
  
215  
  private int height(Node<A> x) {
216  
      if (x == null) return -1;
217  
      return 1 + Math.max(height(x.left), height(x.right));
218  
  }
219  
  
220  
  public bool contains(O val) {
221  
    ret find(root, (A) val) != null;
222  
  }
223  
  
224  
  public A find(A probeVal) {
225  
    Node<A> n = find(root, probeVal);
226  
    ret n == null ? null : n.val;
227  
  }
228  
229  
  // value associated with the given key in subtree rooted at x; null if no such key
230  
  private A get(Node<A> x, A key) {
231  
    x = find(x, key);
232  
    ret x == null ? null : x.val;
233  
  }
234  
235  
  Node<A> find(Node<A> x, A key) {
236  
    while (x != null) {
237  
      int cmp = compare(key, x.val);
238  
      if      (cmp < 0) x = x.left;
239  
      else if (cmp > 0) x = x.right;
240  
      else              ret x;
241  
    }
242  
    null;
243  
  }
244  
245  
  private boolean check() {
246  
      if (!is23())             println("Not a 2-3 tree");
247  
      if (!isBalanced())       println("Not balanced");
248  
      return is23() && isBalanced();
249  
  }
250  
251  
  // Does the tree have no red right links, and at most one (left)
252  
  // red links in a row on any path?
253  
  private boolean is23() { return is23(root); }
254  
  private boolean is23(Node<A> x) {
255  
      if (x == null) true;
256  
      if (isRed(x.right)) false;
257  
      if (x != root && isRed(x) && isRed(x.left)) false;
258  
      ret is23(x.left) && is23(x.right);
259  
  } 
260  
261  
  // do all paths from root to leaf have same number of black edges?
262  
  private bool isBalanced() { 
263  
      int black = 0;     // number of black links on path from root to min
264  
      Node<A> x = root;
265  
      while (x != null) {
266  
          if (!isRed(x)) black++;
267  
          x = x.left;
268  
      }
269  
      ret isBalanced(root, black);
270  
  }
271  
272  
  // does every path from the root to a leaf have the given number of black links?
273  
  private boolean isBalanced(Node<A> x, int black) {
274  
      if (x == null) return black == 0;
275  
      if (!isRed(x)) black--;
276  
      return isBalanced(x.left, black) && isBalanced(x.right, black);
277  
  }
278  
  
279  
  public void clear() { root = null; size = 0; }
280  
  
281  
  // the smallest key in subtree rooted at x; null if no such key
282  
  private Node<A> min(Node<A> x) { 
283  
    // assert x != null;
284  
    while (x.left != null) x = x.left;
285  
    ret x;
286  
  }
287  
  
288  
  private Node<A> deleteMin(Node<A> h) { 
289  
    if (h.left == null)
290  
      return null;
291  
292  
    if (!isRed(h.left) && !isRed(h.left.left))
293  
      h = moveRedLeft(h);
294  
295  
    h.left = deleteMin(h.left);
296  
    ret balance(h);
297  
  }
298  
  
299  
  public Iterator<A> iterator() {
300  
    ret new MyIterator;
301  
  }
302  
303  
  class MyIterator extends ItIt<A> {
304  
    new L<Node<A>> path;
305  
    
306  
    *() {
307  
      fetch(root);
308  
    }
309  
    
310  
    void fetch(Node<A> node) {
311  
      while (node != null) {
312  
        path.add(node);
313  
        node = node.left;
314  
      }
315  
    }
316  
    
317  
    public bool hasNext() { ret !path.isEmpty(); }
318  
319  
    public A next() {
320  
      if (path.isEmpty()) fail("no more elements");
321  
      Node<A> node = popLast(path);
322  
      // last node is always a leaf, so left is null
323  
      // so proceed to fetch right branch
324  
      fetch(node.right);
325  
      ret node.val;
326  
    }
327  
  }
328  
  
329  
  // Returns the smallest key in the symbol table greater than or equal to {@code key}.
330  
  public A ceiling(A key) {
331  
    Node<A> x = ceiling(root, key);
332  
    ret x == null ? null : x.val;
333  
  }
334  
335  
  // the smallest key in the subtree rooted at x greater than or equal to the given key
336  
  Node<A> ceiling(Node<A> x, A key) {  
337  
    if (x == null) null;
338  
    int cmp = compare(key, x.val);
339  
    if (cmp == 0) ret x;
340  
    if (cmp > 0)  ret ceiling(x.right, key);
341  
    Node<A> t = ceiling(x.left, key);
342  
    if (t != null) ret t; 
343  
    else           ret x;
344  
  }
345  
  
346  
  public A floor(A key) {
347  
    Node<A> x = floor(root, key);
348  
    ret x == null ? null : x.val;
349  
  }    
350  
351  
  // the largest key in the subtree rooted at x less than or equal to the given key
352  
  Node<A> floor(Node<A> x, A key) {
353  
    if (x == null) null;
354  
    int cmp = compare(key, x.val);
355  
    if (cmp == 0) ret x;
356  
    if (cmp < 0)  ret floor(x.left, key);
357  
    Node<A> t = floor(x.right, key);
358  
    if (t != null) ret t; 
359  
    else           ret x;
360  
  }
361  
}

Author comment

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: #1030938
Snippet name: UltraCompactTreeSet [seems to work. 24 bytes per entry as opposed to 40 bytes in TreeSet]
Eternal ID of this version: #1030938/18
Text MD5: dbc9c8fa213d0fb893927540b9f21272
Transpilation MD5: 63d749b30723610d01e3ae5f6a7ed784
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-04-13 15:32:08
Source code size: 10509 bytes / 361 lines
Pitched / IR pitched: No / No
Views / Downloads: 206 / 458
Version history: 17 change(s)
Referenced in: [show references]