Class Name: 
kiasan.examples.aatree.AATree

Report Rendered: Mon May 04 12:43:42 CDT 2009, by Sireum/Kiasan for Java v0.1.20090504

Methods Covered:
PercentRatio
Class / Method T E Instruction Coverage Branch Coverage Time
16 0
  31/31
  100%
  6/6
  100%
0.012s
3 1
  37/37
  100%
  6/6
  100%
0.223s
3 1
  37/37
  100%
  6/6
  100%
0.244s
16 0
  117/127
  92.13%
  9/10
  90%
0.341s
16 0
  156/171
  91.23%
  18/20
  90%
0.098s
Total
54 2
  378/403
  93.8%
  45/48
  93.75%
0.918s
Source Code:
1   package kiasan.examples.aatree;
2   
3   import kiasan.examples.common.Range;
4   import kiasan.examples.common.Underflow;
5   
6   // AATree class
7   //
8   // CONSTRUCTION: with no initializer
9   //
10  // ******************PUBLIC OPERATIONS*********************
11  // void insert( x )       --> Insert x
12  // void remove( x )       --> Remove x
13  // boolean contains( x )  --> Return true if x is found
14  // Comparable findMin( )  --> Return smallest item
15  // Comparable findMax( )  --> Return largest item
16  // boolean isEmpty( )     --> Return true if empty; else false
17  // void makeEmpty( )      --> Remove all items
18  // ******************ERRORS********************************
19  // Throws UnderflowException as appropriate
20  
21  /**
22   * Implements an AA-tree. Note that all "matching" is based on the compareTo
23   * method.
24   * 
25   * @author Mark Allen Weiss
26   */
27  public class AATree {
28    private static class AANode {
29      int element; // The data in the node
30  
31      AANode left; // Left child
32      AANode right; // Right child
33      int level; // Level
34  
35      // Constructors
36      AANode(final int theElement, final AANode lt, final AANode rt) {
37        this.element = theElement;
38        this.left = lt;
39        this.right = rt;
40        this.level = 1;
41      }
42    }
43  
44    // Test program; should print min and max and nothing else
45    public static void main(final String[] args) {
46      final AATree t = new AATree();
47      final int NUMS = 40000;
48      final int GAP = 307;
49  
50      System.out.println("Checking... (no bad output means success)");
51  
52      t.insert(NUMS * 2);
53      t.insert(NUMS * 3);
54      for (int i = GAP; i != 0; i = (+ GAP) % NUMS) {
55        t.insert(i);
56      }
57      System.out.println("Inserts complete");
58      assert t.wellFormed();
59      t.remove(t.findMax());
60      for (int i = 1; i < NUMS; i += 2) {
61        t.remove(i);
62      }
63      t.remove(t.findMax());
64      System.out.println("Removes complete");
65  
66      if ((t.findMin() != 2) || (t.findMax() != NUMS - 2)) {
67        System.out.println("FindMin or FindMax error!");
68      }
69  
70      for (int i = 2; i < NUMS; i += 2) {
71        if (!t.contains(i)) {
72          System.out.println("Error: find fails for " + i);
73        }
74      }
75  
76      for (int i = 1; i < NUMS; i += 2) {
77        if (t.contains(i)) {
78          System.out.println("Error: Found deleted item " + i);
79        }
80      }
81    }
82  
83    private AANode root;
84  
85    private final AANode nullNode;
86  
87    private AANode deletedNode;
88  
89    private AANode lastNode;
90  
91    /**
92     * Construct the tree.
93     */
94    public AATree() {
95      this.nullNode = new AANode(0, null, null);
96      this.nullNode.left = this.nullNode.right = this.nullNode;
97      this.nullNode.level = 0;
98      this.root = this.nullNode;
99    }
100 
101   /**
102    * Find an item in the tree.
103    * 
104    * @param x
105    *          the item to search for.
106    * @return true if x is found.
107    */
108   //@ requires this.wellFormed();
109   //@ ensures this.wellFormed();
110   public boolean contains(final int x) {
111     AANode current = this.root;
112     this.nullNode.element = x;
113 
114     for (;;) {
115       // int compareResult = x.compareTo(current.element);
116 
117       if (< current.element) {
118         current = current.left;
119       } else if (> current.element) {
120         current = current.right;
121       } else if (current != this.nullNode) {
122         return true;
123       } else {
124         return false;
125       }
126     }
127   }
128 
129   /**
130    * Find the largest item in the tree.
131    * 
132    * @return the largest item or throw Underflow if empty.
133    */
134   //@ requires this.wellFormed();
135   //@ ensures this.wellFormed();
136   public int findMax() {
137     if (isEmpty()) {
138       throw new Underflow();
139     }
140 
141     AANode ptr = this.root;
142 
143     while (ptr.right != this.nullNode) {
144       ptr = ptr.right;
145     }
146 
147     return ptr.element;
148   }
149 
150   /**
151    * Find the smallest item in the tree.
152    * 
153    * @return the smallest item or throw UnderflowException if empty.
154    */
155   //@ requires this.wellFormed();
156   //@ ensures this.wellFormed();
157   public int findMin() {
158     if (isEmpty()) {
159       throw new Underflow();
160     }
161 
162     AANode ptr = this.root;
163 
164     while (ptr.left != this.nullNode) {
165       ptr = ptr.left;
166     }
167 
168     return ptr.element;
169   }
170 
171   /**
172    * Insert into the tree.
173    * 
174    * @param x
175    *          the item to insert.
176    */
177   //@ requires this.wellFormed();
178   //@ ensures (this.root != this.nullNode) && this.wellFormed();
179   public void insert(final int x) {
180     this.root = insert(x, this.root);
181   }
182 
183   /**
184    * Internal method to insert into a subtree.
185    * 
186    * @param x
187    *          the item to insert.
188    * @param t
189    *          the node that roots the subtree.
190    * @return the new root of the subtree.
191    */
192   private AANode insert(final int x, AANode t) {
193     if (== this.nullNode) {
194       return new AANode(x, this.nullNode, this.nullNode);
195     }
196 
197     // int compareResult = x.compareTo(t.element);
198 
199     if (< t.element) {
200       t.left = insert(x, t.left);
201     } else if (> t.element) {
202       t.right = insert(x, t.right);
203     } else {
204       return t;
205     }
206 
207     t = skew(t);
208     t = split(t);
209     return t;
210   }
211 
212   /**
213    * Test if the tree is logically empty.
214    * 
215    * @return true if empty, false otherwise.
216    */
217   public boolean isEmpty() {
218     return this.root == this.nullNode;
219   }
220 
221   /**
222    * Make the tree logically empty.
223    */
224   public void makeEmpty() {
225     this.root = this.nullNode;
226   }
227 
228   private boolean ordered() {
229     return ordered(this.root, new Range());
230   }
231 
232   private boolean ordered(final AANode t, final Range range) {
233     if (== null) {
234       return false;
235     }
236     if (== this.nullNode) {
237       return true;
238     }
239     if (!range.inRange(t.element)) {
240       return false;
241     }
242     boolean ret = ordered(t.left, range.setUpper(t.element));
243     ret = ret && ordered(t.right, range.setLower(t.element));
244     return ret;
245   }
246 
247   /**
248    * Remove from the tree.
249    * 
250    * @param x
251    *          the item to remove.
252    */
253   //@ requires (this.lastNode == null) && (this.deletedNode == null) && this.wellFormed();
254   //@ ensures this.wellFormed();
255   public void remove(final int x) {
256     this.deletedNode = this.nullNode;
257     this.root = remove(x, this.root);
258   }
259 
260   /**
261    * Internal method to remove from a subtree.
262    * 
263    * @param x
264    *          the item to remove.
265    * @param t
266    *          the node that roots the subtree.
267    * @return the new root of the subtree.
268    */
269   private AANode remove(final int x, AANode t) {
270     if (!= this.nullNode) {
271       // Step 1: Search down the tree and set lastNode and deletedNode
272       this.lastNode = t;
273       if (< t.element) {
274         t.left = remove(x, t.left);
275       } else {
276         this.deletedNode = t;
277         t.right = remove(x, t.right);
278       }
279 
280       // Step 2: If at the bottom of the tree and
281       // x is present, we remove it
282       if (== this.lastNode) {
283         if ((this.deletedNode == this.nullNode)
284             || (!= this.deletedNode.element)) {
285           return t; // Item not found; do nothing
286         }
287         this.deletedNode.element = t.element;
288         t = t.right;
289       }
290 
291       // Step 3: Otherwise, we are not at the bottom; rebalance
292       else if ((t.left.level < t.level - 1) || (t.right.level < t.level - 1)) {
293         if (t.right.level > --t.level) {
294           t.right.level = t.level;
295         }
296         t = skew(t);
297         t.right = skew(t.right);
298         t.right.right = skew(t.right.right);
299         t = split(t);
300         t.right = split(t.right);
301       }
302     }
303     return t;
304   }
305 
306   /**
307    * Rotate binary tree node with left child.
308    */
309   private AANode rotateWithLeftChild(final AANode k2) {
310     final AANode k1 = k2.left;
311     k2.left = k1.right;
312     k1.right = k2;
313     return k1;
314   }
315 
316   /**
317    * Rotate binary tree node with right child.
318    */
319   private AANode rotateWithRightChild(final AANode k1) {
320     final AANode k2 = k1.right;
321     k1.right = k2.left;
322     k2.left = k1;
323     return k2;
324   }
325 
326   /**
327    * Skew primitive for AA-trees.
328    * 
329    * @param t
330    *          the node that roots the tree.
331    * @return the new root after the rotation.
332    */
333   private AANode skew(AANode t) {
334     if (t.left.level == t.level) {
335       t = rotateWithLeftChild(t);
336     }
337     return t;
338   }
339 
340   /**
341    * Split primitive for AA-trees.
342    * 
343    * @param t
344    *          the node that roots the tree.
345    * @return the new root after the rotation.
346    */
347   private AANode split(AANode t) {
348     if (t.right.right.level == t.level) {
349       t = rotateWithRightChild(t);
350       t.level++;
351     }
352     return t;
353   }
354 
355   private boolean validGlobals() {
356     if ((this.nullNode == null) || (this.nullNode.level != 0)) {
357       return false;
358     }
359     if ((this.nullNode.left != this.nullNode)
360         || (this.nullNode.right != this.nullNode)) {
361       return false;
362     }
363     return true;
364   }
365 
366   private boolean wellFormed() {
367     if (!validGlobals()) {
368       return false;
369     }
370     if (this.root == null) {
371       return false;
372     }
373     return ordered() && wellLevel(this.root, this.root.level + 1);
374   }
375 
376   // structural invariant of AATree
377   // 1. The level of a leaf node is one.
378   // 2. The level of a left child is strictly == its parent's level - 1.
379   // 3. The level of a right child is less than one or equal to that of its
380   // parent.
381   // 4. The level of a right grandchild is strictly less than that of its
382   // grandparent.
383   // 5. Every node of level greater than one must have two children.
384   private boolean wellLevel(final AANode node, final int parentLevel) {
385     if ((node.left == null) || (node.right == null)) {
386       return false;
387     }
388     if (node == this.nullNode) {
389       if (node.level != 0) {
390         return false;
391       } else {
392         return true;
393       }
394     }
395     if ((node.left == this.nullNode) || (node.right == this.nullNode)) {
396       if (node.level != 1) {
397         return false;
398       }
399     }
400     if (node.left != this.nullNode) {
401       if (node.level != node.left.level + 1) {
402         return false;
403       }
404       if (!wellLevel(node.left, node.level)) {
405         return false;
406       }
407     }
408     if ((node.right != this.nullNode) && !(parentLevel > node.right.level)) {
409       return false;
410     }
411     if (node.right != this.nullNode) {
412       if (!((node.level == node.right.level) || (node.level == node.right.level + 1))) {
413         return false;
414       }
415       return wellLevel(node.right, node.level);
416     }
417     return true;
418   }
419 }