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

302
LINES

< > BotCompany Repo | #1024436 // LogNArray v4 for export

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

Libraryless. Click here for Pure Java version (320L/3K).

1  
do not include function get.
2  
do not include function add.
3  
do not include function remove.
4  
do not include function set.
5  
do not include function println.
6  
7  
// see: https://en.wikipedia.org/wiki/Order_statistic_tree
8  
// based on: https://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
9  
final sclass LogNArray<Value> extends RandomAccessAbstractList<Value> {
10  
11  
 // A symbol table implemented using a left-leaning red-black BST.
12  
 // This is the 2-3 version.
13  
 
14  
  private static final boolean RED   = true;
15  
  private static final boolean BLACK = false;
16  
17  
  private Node<Value> root;     // root of the BST
18  
19  
  // BST helper node data type
20  
  private final sclass Node<Value> {
21  
    private Value val;         // associated data
22  
    private Node<Value> left, right;  // links to left and right subtrees
23  
    private int sizeAndColor; // subtree count + color (highest bit)
24  
    
25  
    *() {}
26  
27  
    *(Value val, boolean color, int size) {
28  
      this.val = val;
29  
      sizeAndColor = size | (color ? 0x80000000 : 0);
30  
    }
31  
    
32  
    int size() { ret sizeAndColor & 0x7FFFFFFF; }
33  
    bool color() { ret sizeAndColor < 0; }
34  
    
35  
    void setSize(int size) { sizeAndColor = sizeAndColor & 0x80000000 | size; }
36  
    void setColor(bool color) { sizeAndColor = size() | (color ? 0x80000000 : 0); }
37  
  }
38  
39  
  // is node x red; false if x is null ?
40  
  private boolean isRed(Node<Value> x) {
41  
      if (x == null) return false;
42  
      return x.color() == RED;
43  
  }
44  
45  
  // number of node in subtree rooted at x; 0 if x is null
46  
  private int size(Node<Value> x) {
47  
      if (x == null) return 0;
48  
      return x.size();
49  
  } 
50  
51  
52  
  public int size() {
53  
      return size(root);
54  
  }
55  
56  
  public boolean isEmpty() {
57  
      return root == null;
58  
  }
59  
60  
61  
  public void add(int idx, Value val) {
62  
    if (idx < 0 || idx > size()) throw new IndexOutOfBoundsException(idx + " / " + size());
63  
    
64  
    root = add(root, idx, val);
65  
    root.setColor(BLACK);
66  
    ifdef LogNArray_debug assertTrue(check()); endifdef
67  
  }
68  
69  
  // insert the value pair in index k of subtree rooted at h
70  
  private Node<Value> add(Node<Value> h, int k, Value val) { 
71  
    if (h == null) ret new Node(val, RED, 1);
72  
73  
    int t = size(h.left);
74  
    if (k < t)
75  
      // replace / fit in left child
76  
      h.left = add(h.left, k, val);
77  
    else if (k == t) {
78  
      // move value to right child, replace value
79  
      h.right = add(h.right, 0, h.val);
80  
      h.val = val;
81  
    } else
82  
      // replace / fit in right child
83  
      h.right = add(h.right, k-t-1, val); 
84  
85  
    // fix-up any right-leaning links
86  
    if (isRed(h.right) && !isRed(h.left))      h = rotateLeft(h);
87  
    if (isRed(h.left)  &&  isRed(h.left.left)) h = rotateRight(h);
88  
    if (isRed(h.left)  &&  isRed(h.right))     flipColors(h);
89  
    h.setSize(size(h.left) + size(h.right) + 1);
90  
    
91  
    ifdef LogNArray_debug
92  
      print("LogNArray.add: Node " + h.val + " new size: " + h.size());
93  
    endifdef
94  
95  
    ret h;
96  
  }
97  
98  
  public Value remove(int idx) { 
99  
    Value oldValue = get(idx);
100  
    
101  
    // if both children of root are black, set root to red
102  
    if (!isRed(root.left) && !isRed(root.right))
103  
      root.setColor(RED);
104  
105  
    root = remove(root, idx);
106  
    if (root != null) root.setColor(BLACK);
107  
    
108  
    ifdef LogNArray_debug assertTrue(check()); endifdef
109  
    
110  
    ret oldValue;
111  
  }
112  
113  
  private Node<Value> remove(Node<Value> h, int k) { 
114  
    int t = size(h.left);
115  
    if (k < t) { // remove from left child
116  
      if (!isRed(h.left) && !isRed(h.left.left))
117  
        h = moveRedLeft(h);
118  
      h.left = remove(h.left, k);
119  
    } else { // remove from center or right child
120  
      if (isRed(h.left)) {
121  
        h = rotateRight(h);
122  
        t = size(h.left);
123  
      }
124  
      if (h.right == null) null; // drop whole node
125  
      if (!isRed(h.right) && !isRed(h.right.left)) {
126  
        h = moveRedRight(h);
127  
        t = size(h.left);
128  
      }
129  
      if (k == t) { // replace center value with min of right child
130  
        h.val = nodeAtIndex(h.right, 0).val;
131  
        h.right = remove(h.right, 0);
132  
      }
133  
      else h.right = remove(h.right, k-t-1);
134  
    }
135  
    ret balance(h);
136  
  }
137  
138  
  // make a left-leaning link lean to the right
139  
  private Node<Value> rotateRight(Node<Value> h) {
140  
      // assert (h != null) && isRed(h.left);
141  
      Node<Value> x = h.left;
142  
      h.left = x.right;
143  
      x.right = h;
144  
      x.setColor(x.right.color());
145  
      x.right.setColor(RED);
146  
      x.setSize(h.size());
147  
      h.setSize(size(h.left) + size(h.right) + 1);
148  
      return x;
149  
  }
150  
151  
  // make a right-leaning link lean to the left
152  
  private Node<Value> rotateLeft(Node<Value> h) {
153  
      // assert (h != null) && isRed(h.right);
154  
      Node<Value> x = h.right;
155  
      h.right = x.left;
156  
      x.left = h;
157  
      x.setColor(x.left.color());
158  
      x.left.setColor(RED);
159  
      x.setSize(h.size());
160  
      h.setSize(size(h.left) + size(h.right) + 1);
161  
      return x;
162  
  }
163  
164  
  // flip the colors of a node and its two children
165  
  private void flipColors(Node<Value> h) {
166  
      // h must have opposite color of its two children
167  
      // assert (h != null) && (h.left != null) && (h.right != null);
168  
      // assert (!isRed(h) &&  isRed(h.left) &&  isRed(h.right))
169  
      //    || (isRed(h)  && !isRed(h.left) && !isRed(h.right));
170  
      h.setColor(!h.color());
171  
      h.left.setColor(!h.left.color());
172  
      h.right.setColor(!h.right.color());
173  
  }
174  
175  
  // Assuming that h is red and both h.left and h.left.left
176  
  // are black, make h.left or one of its children red.
177  
  private Node<Value> moveRedLeft(Node<Value> h) {
178  
      // assert (h != null);
179  
      // assert isRed(h) && !isRed(h.left) && !isRed(h.left.left);
180  
181  
      flipColors(h);
182  
      if (isRed(h.right.left)) { 
183  
          h.right = rotateRight(h.right);
184  
          h = rotateLeft(h);
185  
          flipColors(h);
186  
      }
187  
      return h;
188  
  }
189  
190  
  // Assuming that h is red and both h.right and h.right.left
191  
  // are black, make h.right or one of its children red.
192  
  private Node<Value> moveRedRight(Node<Value> h) {
193  
      // assert (h != null);
194  
      // assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);
195  
      flipColors(h);
196  
      if (isRed(h.left.left)) { 
197  
          h = rotateRight(h);
198  
          flipColors(h);
199  
      }
200  
      return h;
201  
  }
202  
203  
  // restore red-black tree invariant
204  
  private Node<Value> balance(Node<Value> h) {
205  
      // assert (h != null);
206  
207  
      if (isRed(h.right))                      h = rotateLeft(h);
208  
      if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
209  
      if (isRed(h.left) && isRed(h.right))     flipColors(h);
210  
211  
      h.setSize(size(h.left) + size(h.right) + 1);
212  
      return h;
213  
  }
214  
215  
216  
  /**
217  
   * Returns the height of the BST (for debugging).
218  
   * @return the height of the BST (a 1-node tree has height 0)
219  
   */
220  
  public int height() {
221  
      return height(root);
222  
  }
223  
  
224  
  private int height(Node<Value> x) {
225  
      if (x == null) return -1;
226  
      return 1 + Math.max(height(x.left), height(x.right));
227  
  }
228  
  
229  
  public Value get(int k) {
230  
    ret nodeAtIndex(k).val;
231  
  }
232  
233  
  public Value set(int k, Value val) {
234  
    Node<Value> n = nodeAtIndex(k);
235  
    Value oldValue = n.val;
236  
    n.val = val;
237  
    ret oldValue;
238  
  }
239  
240  
  public Node<Value> nodeAtIndex(int k) {
241  
      if (k < 0 || k >= size()) {
242  
          throw new IndexOutOfBoundsException(k + " / " + size());
243  
      }
244  
      ret nodeAtIndex(root, k);
245  
  }
246  
247  
  // the key of rank k in the subtree rooted at x
248  
  private Node<Value> nodeAtIndex(Node<Value> x, int k) {
249  
      // assert x != null;
250  
      // assert k >= 0 && k < size(x);
251  
      int t = size(x.left); 
252  
      if      (t > k) return nodeAtIndex(x.left,  k); 
253  
      else if (t < k) return nodeAtIndex(x.right, k-t-1); 
254  
      else            return x; 
255  
  } 
256  
  
257  
  private boolean check() {
258  
      if (!isSizeConsistent()) System.out.println("Subtree counts not consistent");
259  
      if (!is23())             System.out.println("Not a 2-3 tree");
260  
      if (!isBalanced())       System.out.println("Not balanced");
261  
      return isSizeConsistent() && is23() && isBalanced();
262  
  }
263  
264  
  // are the size fields correct?
265  
  private boolean isSizeConsistent() { return isSizeConsistent(root); }
266  
  private boolean isSizeConsistent(Node<Value> x) {
267  
      if (x == null) return true;
268  
      if (x.size() != size(x.left) + size(x.right) + 1) return false;
269  
      return isSizeConsistent(x.left) && isSizeConsistent(x.right);
270  
  } 
271  
272  
  // Does the tree have no red right links, and at most one (left)
273  
  // red links in a row on any path?
274  
  private boolean is23() { return is23(root); }
275  
  private boolean is23(Node<Value> x) {
276  
      if (x == null) return true;
277  
      if (isRed(x.right)) return false;
278  
      if (x != root && isRed(x) && isRed(x.left))
279  
          return false;
280  
      return is23(x.left) && is23(x.right);
281  
  } 
282  
283  
  // do all paths from root to leaf have same number of black edges?
284  
  private boolean isBalanced() { 
285  
      int black = 0;     // number of black links on path from root to min
286  
      Node<Value> x = root;
287  
      while (x != null) {
288  
          if (!isRed(x)) black++;
289  
          x = x.left;
290  
      }
291  
      return isBalanced(root, black);
292  
  }
293  
294  
  // does every path from the root to a leaf have the given number of black links?
295  
  private boolean isBalanced(Node<Value> x, int black) {
296  
      if (x == null) return black == 0;
297  
      if (!isRed(x)) black--;
298  
      return isBalanced(x.left, black) && isBalanced(x.right, black);
299  
  }
300  
  
301  
  public void clear() { root = null; }
302  
}

Author comment

Began life as a copy of #1024427

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1024436
Snippet name: LogNArray v4 for export
Eternal ID of this version: #1024436/5
Text MD5: a566b7f8a05b5a499d9d57a25ed7b07d
Transpilation MD5: 1c7828d71966901460eb0c4d0cae74ca
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-08-12 17:16:28
Source code size: 9568 bytes / 302 lines
Pitched / IR pitched: No / No
Views / Downloads: 129 / 198
Version history: 4 change(s)
Referenced in: [show references]