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

344
LINES

< > BotCompany Repo | #1029166 // CompactTreeSet [probably OK. 32 bytes per node as opposed to 40 in TreeSet]

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

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

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

Author comment

Began life as a copy of #1024413

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1029166
Snippet name: CompactTreeSet [probably OK. 32 bytes per node as opposed to 40 in TreeSet]
Eternal ID of this version: #1029166/45
Text MD5: 60284221ea95064f45637755865d0cd6
Transpilation MD5: 0a99d09c05c66e3a2426d80253c3aebb
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-06-24 22:08:32
Source code size: 9899 bytes / 344 lines
Pitched / IR pitched: No / No
Views / Downloads: 291 / 670
Version history: 44 change(s)
Referenced in: [show references]