meaningless comment
[ephemerata.git] / KezvhLib / src-lib / net / kezvh / collections / heaps / PairingHeap.java
blob3e13f7d90cf26286cf151556f5d6ff18c5a2608a
1 package net.kezvh.collections.heaps;
3 import java.util.Collection;
4 import java.util.Comparator;
5 import java.util.HashMap;
6 import java.util.Iterator;
7 import java.util.Map;
9 import net.kezvh.collections.ComparableComparator;
10 import net.kezvh.collections.MapEntryImpl;
11 import net.kezvh.development.UnimplementedException;
12 import net.kezvh.lang.AlgorithmException;
14 /**
15 * @author mjacob
17 * see
18 * http://www.cise.ufl.edu/~sahni/dsaaj/enrich/c13/pairing.htm
19 * http://en.wikipedia.org/wiki/Pairing_heap
21 * @param <E> COMMENT
22 * @param <W> COMMENT
24 public class PairingHeap<E, W extends Comparable<W>> extends AbstractHeap<E, W> {
25 /**
26 * alright, node now knows 1 child, and is in a circularly linked list with its siblings.
27 * either i'm an idiot, or there's no way to remove a node from the tree without knowing
28 * your parent is.
29 * @author mjacob
32 private final class PairingHeapNode extends MapEntryImpl<E, W> implements Comparable<PairingHeapNode> {
33 private PairingHeapNode child = null;
34 private PairingHeapNode nextSibling = null;
35 private PairingHeapNode previousSibling = null;
36 private PairingHeapNode parent = null;
38 public PairingHeapNode(final E key, final W value) {
39 super(key, value);
42 @Override
43 public W setValue(final W arg0) {
44 return this.setImplValue(arg0);
47 /**
48 * any parent/siblings defined in the newchild will be overriden
49 * @param newChild the new child
51 public void addChild(final PairingHeapNode newChild) {
52 if (newChild == this)
53 throw new AlgorithmException();
55 newChild.parent = this;
56 if (this.child == null)
57 this.child = newChild.previousSibling = newChild.nextSibling = newChild;
58 else { // insert before child (@ end of loop)
59 newChild.nextSibling = this.child;
60 newChild.previousSibling = this.child.previousSibling;
61 this.child.previousSibling.nextSibling = newChild;
62 this.child.previousSibling = newChild;
66 @Override
67 public int compareTo(final PairingHeapNode o) {
68 return PairingHeap.this.comparator.compare(this.getValue(), o.getValue());
71 /**
72 * @return the next sibling after the two merged nodes
74 public PairingHeapNode mergeWithSibling() {
75 if (this.nextSibling == this)
76 return this;
78 final PairingHeapNode mergeParent = this.parent; // we won't be able to rely on the "this" pointer after the merge
79 final PairingHeapNode oldSibling = this.nextSibling; // the sibling to merge with
80 final PairingHeapNode mergeNext = oldSibling.nextSibling;
82 if (this == mergeNext) {
83 // this and oldSibling are the only two children
84 final PairingHeapNode newNode = PairingHeap.this.merge(this, oldSibling);
86 newNode.previousSibling = newNode.nextSibling = newNode;
87 mergeParent.child = newNode;
88 } else {
89 final boolean first = (this.parent.child == this || this.parent.child == oldSibling); // wheter we need to reset the parent's child after we merge
90 final PairingHeapNode mergePrevious = this.previousSibling; // we'll need to reset the "next" value on this
92 final PairingHeapNode newNode = PairingHeap.this.merge(this, oldSibling);
94 if (first) // we might have merged the child the parent knew about lower into the tree
95 mergeParent.child = newNode;
97 newNode.previousSibling = mergePrevious;
98 newNode.nextSibling = mergeNext;
100 mergePrevious.nextSibling = mergeNext.previousSibling = newNode;
102 return mergeNext;
105 public PairingHeapNode getChild() {
106 return this.child;
109 public boolean hasMultipleChildren() {
110 return this.child != null && this.child != this.child.nextSibling;
113 public void setAsRoot() {
114 this.parent = null;
117 public void pruneSelf() {
118 if (this.parent.child == this) // removing the first child
119 if (this.nextSibling == this) // removing the only child
120 this.parent.child = null;
121 else
122 this.parent.child = this.nextSibling; // if there's more than 1 child, have parent point to the next one
123 if (this.nextSibling != this) { // we need to close the loop.
124 this.nextSibling.previousSibling = this.previousSibling;
125 this.previousSibling.nextSibling = this.nextSibling;
127 this.parent = null;
128 this.nextSibling = this.previousSibling = this;
131 @Override
132 public String toString() {
133 return "node " + this.getKey() + " (" + this.getValue() + ")";
137 * debug method
139 * @param prefix COMMENT
140 * @param loopStart COMMENT
141 * @param termination COMMENT
143 public void printTree(final String prefix, final PairingHeapNode loopStart, final int termination) {
144 if (termination == 0)
145 throw new AlgorithmException();
146 System.out.println(prefix + this);
147 if (this.child != null)
148 this.child.printTree(" " + prefix, null, termination - 1);
149 if (this.nextSibling != loopStart && this.nextSibling != this)
150 this.nextSibling.printTree(prefix, loopStart == null ? this : loopStart, termination - 1);
154 private PairingHeapNode root;
155 private final Map<E, PairingHeapNode> map = new HashMap<E, PairingHeapNode>();
156 private final Comparator<? super W> comparator;
161 public PairingHeap() {
162 this(new ComparableComparator<W>());
166 * @param comparator COMMENT
168 public PairingHeap(final Comparator<? super W> comparator) {
169 this.comparator = comparator;
172 @Override
173 public void merge(final Heap<E, W> other) {
174 if (other == null || this.getClass() != other.getClass())
175 throw new IllegalArgumentException();
177 final PairingHeap<E, W> otherHeap = (PairingHeap<E, W>) other;
178 this.root = this.merge(this.root, otherHeap.root);
179 this.map.putAll(otherHeap.map);
180 otherHeap.clear();
183 /* assuming that remove() removes the minimum element; thus, we assume we do the usual
184 * heap thing if the new weight is "less than" the current weight
186 * (non-Javadoc)
187 * @see net.kezvh.collections.heaps.Heap#reweight(java.lang.Object, java.lang.Object)
189 @Override
190 public W reweight(final E t, final W newWeight) {
191 if (!(this.map.containsKey(t)))
192 throw new IllegalArgumentException("element " + t + " must be in the heap in order to reweight it");
194 final PairingHeapNode node = this.map.get(t);
195 final W oldWeight = node.getValue();
197 try {
198 return node.setValue(newWeight);
199 } finally {
200 if (this.root == node) {
201 if (this.size() != 1)
202 if (this.comparator.compare(newWeight, oldWeight) > 0)
203 throw new UnimplementedException("haven't yet implemented increasing the root node's weight (node " + t + " old weight: " + oldWeight + " new eight: " + newWeight);
204 } else {
205 node.pruneSelf();
206 this.root = this.merge(this.root, node);
211 private PairingHeapNode merge(final PairingHeapNode a, final PairingHeapNode b) {
212 if (a == null)
213 return b;
214 if (b == null)
215 return a;
216 if (a.compareTo(b) <= 0) {
217 a.addChild(b);
218 return a;
220 b.addChild(a);
221 return b;
224 @Override
225 public W add(final E t, final W weight) {
226 if (this.map.containsKey(t))
227 return this.reweight(t, weight);
229 final PairingHeapNode newNode = new PairingHeapNode(t, weight);
230 this.root = this.merge(this.root, newNode);
231 this.map.put(t, newNode);
232 return null;
235 @Override
236 public E peek() {
237 if (this.root == null)
238 return null;
239 return this.root.getKey();
243 * this can do 1 of 3 things
244 * 1) iterate over the heap out of order (easy)
245 * 2) destroy the heap as you iterate (easy)
246 * 3) clone the heap, destroy that as you iterate (harder)
248 @Override
249 public Iterator<E> iterator() {
250 throw new UnimplementedException(); // FIXME
253 @Override
254 public void clear() {
255 this.map.clear();
256 this.root = null;
259 @Override
260 public boolean contains(final Object o) {
261 return this.map.containsKey(o);
264 @Override
265 public boolean containsAll(final Collection<?> c) {
266 return this.map.entrySet().containsAll(c);
269 @Override
270 public boolean isEmpty() {
271 return this.map.isEmpty();
274 @Override
275 public E remove() {
276 try {
277 final E minValue = this.root.getKey();
278 this.map.remove(minValue);
279 return minValue;
280 } finally {
281 PairingHeapNode nextNode = this.root.getChild();
282 while (this.root.hasMultipleChildren())
283 nextNode = nextNode.mergeWithSibling(); // the value retured is the node AFTER the two that were merged
284 this.root = this.root.getChild();
285 if (this.root != null)
286 this.root.setAsRoot();
291 * this should be easy.
292 * basically, you prune the node for the object, the removeMin() from that tree, then join.
294 @Override
295 public boolean remove(final Object o) {
296 throw new UnimplementedException(); // FIXME
299 @Override
300 public int size() {
301 return this.map.size();
304 @Override
305 public Comparator<? super W> comparator() {
306 return this.comparator;