Class Name: 
kiasan.examples.leftistheap.LeftistHeap

Report Rendered: Mon May 04 11:28:34 CDT 2009, by Sireum/Kiasan for Java v0.1.20090504

Methods Covered:
PercentRatio
Class / Method T E Instruction Coverage Branch Coverage Time
24 1
  102/102
  100%
  14/14
  100%
1.388s
11 1
  24/24
  100%
  4/4
  100%
0.203s
31 0
  98/98
  100%
  10/10
  100%
1.418s
merge(LeftistHeap)
588 0
  82/82
  100%
  12/12
  100%
1.219s
Total
654 2
  306/306
  100%
  40/40
  100%
4.228s
Source Code:
1   package kiasan.examples.leftistheap;
2   
3   import kiasan.examples.common.LinkedList;
4   import kiasan.examples.common.Underflow;
5   
6   // LeftistHeap class
7   //
8   // CONSTRUCTION: with a negative infinity sentinel
9   //
10  // ******************PUBLIC OPERATIONS*********************
11  // void insert( x )       --> Insert x
12  // Comparable deleteMin( )--> Return and remove smallest item
13  // Comparable findMin( )  --> Return smallest item
14  // boolean isEmpty( )     --> Return true if empty; else false
15  // void makeEmpty( )      --> Remove all items
16  // void merge( rhs )      --> Absorb rhs into this heap
17  // ******************ERRORS********************************
18  // Throws UnderflowException as appropriate
19  
20  /**
21   * Implements a leftist heap. Note that all "matching" is based on the compareTo
22   * method.
23   * 
24   * @author Mark Allen Weiss
25   */
26  public class LeftistHeap {
27    private static class LeftistNode {
28      int element; // The data in the node
29  
30      LeftistNode left; // Left child
31  
32      LeftistNode right; // Right child
33      int npl; // null path length
34  
35      // Constructors
36      LeftistNode(final int theElement) {
37        this(theElement, null, null);
38      }
39  
40      LeftistNode(final int theElement, final LeftistNode lt, final LeftistNode rt) {
41        this.element = theElement;
42        this.left = lt;
43        this.right = rt;
44        this.npl = 0;
45      }
46    }
47  
48    public static void main(final String[] args) {
49      final int numItems = 100;
50      final LeftistHeap h = new LeftistHeap();
51      final LeftistHeap h1 = new LeftistHeap();
52      int i = 37;
53  
54      for (= 37; i != 0; i = (+ 37) % numItems) {
55        if (% 2 == 0) {
56          h1.insert(i);
57        } else {
58          h.insert(i);
59        }
60      }
61      assert h.wellFormed();
62      h.merge(h1);
63      assert h.wellFormed();
64      for (= 1; i < numItems; i++) {
65        if (h.deleteMin() != i) {
66          System.out.println("Oops! " + i);
67        }
68      }
69    }
70  
71    /**
72     * Swaps t's two children.
73     */
74    private static void swapChildren(final LeftistNode t) {
75      final LeftistNode tmp = t.left;
76      t.left = t.right;
77      t.right = tmp;
78    }
79  
80    private LeftistNode root; // root
81  
82    /**
83     * Construct the leftist heap.
84     */
85    public LeftistHeap() {
86      this.root = null;
87    }
88  
89    /**
90     * Remove the smallest item from the priority queue.
91     * 
92     * @return the smallest item, or throw UnderflowException if empty.
93     */
94    //@ requires this.wellFormed();
95    //@ ensures this.wellFormed();
96    public int deleteMin() {
97      if (isEmpty()) {
98        throw new Underflow();
99      }
100 
101     final int minItem = this.root.element;
102     this.root = merge(this.root.left, this.root.right);
103 
104     return minItem;
105   }
106 
107   /**
108    * Find the smallest item in the priority queue.
109    * 
110    * @return the smallest item, or throw UnderflowException if empty.
111    */
112   //@ requires this.wellFormed();
113   //@ ensures this.wellFormed();
114   public int findMin() {
115     if (isEmpty()) {
116       throw new Underflow();
117     }
118     return this.root.element;
119   }
120 
121   /**
122    * Insert into the priority queue, maintaining heap order.
123    * 
124    * @param x
125    *          the item to insert.
126    */
127   //@ requires this.wellFormed();
128   //@ ensures (this.root != null) && this.wellFormed();
129   public void insert(final int x) {
130     this.root = merge(new LeftistNode(x), this.root);
131   }
132 
133   private boolean isAcyclic(final LeftistNode start,
134       final LinkedList<LeftistNode> seen) {
135     if (start.left != null) {
136       if (seen.contains(start.left)) {
137         return false;
138       }
139       seen.addToEnd(start.left);
140       if (!isAcyclic(start.left, seen)) {
141         return false;
142       }
143     }
144     if (start.right != null) {
145       if (seen.contains(start.right)) {
146         return false;
147       }
148       seen.addToEnd(start.right);
149       if (!isAcyclic(start.right, seen)) {
150         return false;
151       }
152     }
153     return true;
154   }
155 
156   /**
157    * Test if the priority queue is logically empty.
158    * 
159    * @return true if empty, false otherwise.
160    */
161   public boolean isEmpty() {
162     return this.root == null;
163   }
164 
165   private boolean isLeftist(final LeftistNode ln) {
166     if (ln == null) {
167       return true;
168     }
169     int lnpl = -1;
170     if (ln.left != null) {
171       lnpl = ln.left.npl;
172     }
173     int rnpl = -1;
174     if (ln.right != null) {
175       rnpl = ln.right.npl;
176     }
177     if ((lnpl < rnpl) || (ln.npl != rnpl + 1)) {
178       return false;
179     }
180     return isLeftist(ln.left) && isLeftist(ln.right);
181   }
182 
183   /**
184    * Make the priority queue logically empty.
185    */
186   public void makeEmpty() {
187     this.root = null;
188   }
189 
190   /**
191    * Merge rhs into the priority queue. rhs becomes empty. rhs must be different
192    * from this.
193    * 
194    * @param rhs
195    *          the other leftist heap.
196    */
197   //@ requires this.merge_preCondition(rhs);
198   //@ ensures this.wellFormed();
199   public void merge(final LeftistHeap rhs) {
200     if (this == rhs) {
201       return;
202     }
203 
204     this.root = merge(this.root, rhs.root);
205     rhs.root = null;
206   }
207 
208   /**
209    * Internal method to merge two roots. Deals with deviant cases and calls
210    * recursive merge1.
211    */
212   private LeftistNode merge(final LeftistNode h1, final LeftistNode h2) {
213     if (h1 == null) {
214       return h2;
215     }
216     if (h2 == null) {
217       return h1;
218     }
219     if (h1.element < h2.element) {
220       return merge1(h1, h2);
221     } else {
222       return merge1(h2, h1);
223     }
224   }
225 
226   boolean merge_preCondition(final LeftistHeap rhs) {
227     if (rhs == null) {
228       return false;
229     }
230     final LinkedList<LeftistNode> seen = new LinkedList<LeftistNode>();
231     if (this.root != null) {
232       seen.addToEnd(this.root);
233       final boolean result = isAcyclic(this.root, seen) && ordered(this.root)
234           && isLeftist(this.root);
235       if (!result) {
236         return false;
237       }
238     }
239     if (rhs.root != null) {
240       if (seen.contains(rhs.root)) {
241         return false;
242       }
243       seen.addToEnd(rhs.root);
244       return isAcyclic(rhs.root, seen) && ordered(rhs.root)
245           && isLeftist(rhs.root);
246     }
247     return true;
248   }
249 
250   /**
251    * Internal method to merge two roots. Assumes trees are not empty, and h1's
252    * root contains smallest item.
253    */
254   private LeftistNode merge1(final LeftistNode h1, final LeftistNode h2) {
255     if (h1.left == null) {
256       h1.left = h2; // Other fields in h1 already accurate
257     } else {
258       h1.right = merge(h1.right, h2);
259       if (h1.left.npl < h1.right.npl) {
260         LeftistHeap.swapChildren(h1);
261       }
262       h1.npl = h1.right.npl + 1;
263     }
264     return h1;
265   }
266 
267   private boolean ordered(final LeftistNode ln) {
268     if (ln == null) {
269       return true;
270     }
271     if ((ln.left != null) && (ln.element > ln.left.element)) {
272       return false;
273     }
274     if ((ln.right != null) && (ln.element > ln.right.element)) {
275       return false;
276     }
277     return ordered(ln.left) && ordered(ln.right);
278   }
279 
280   private boolean wellFormed() {
281     if (this.root == null) {
282       return true;
283     }
284     final LinkedList<LeftistNode> seen = new LinkedList<LeftistNode>();
285     seen.addToEnd(this.root);
286     return isAcyclic(this.root, seen) && ordered(this.root)
287         && isLeftist(this.root);
288   }
289 }