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

333
LINES

< > BotCompany Repo | #1030399 // LongTreeSet [apparently OK]

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

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  
}

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: #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: 179 / 432
Version history: 13 change(s)
Referenced in: [show references]