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
;
9 import net
.kezvh
.collections
.ComparableComparator
;
10 import net
.kezvh
.collections
.MapEntryImpl
;
11 import net
.kezvh
.development
.UnimplementedException
;
12 import net
.kezvh
.lang
.AlgorithmException
;
18 * http://www.cise.ufl.edu/~sahni/dsaaj/enrich/c13/pairing.htm
19 * http://en.wikipedia.org/wiki/Pairing_heap
24 public class PairingHeap
<E
, W
extends Comparable
<W
>> extends AbstractHeap
<E
, W
> {
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
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
) {
43 public W
setValue(final W arg0
) {
44 return this.setImplValue(arg0
);
48 * any parent/siblings defined in the newchild will be overriden
49 * @param newChild the new child
51 public void addChild(final PairingHeapNode newChild
) {
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
;
67 public int compareTo(final PairingHeapNode o
) {
68 return PairingHeap
.this.comparator
.compare(this.getValue(), o
.getValue());
72 * @return the next sibling after the two merged nodes
74 public PairingHeapNode
mergeWithSibling() {
75 if (this.nextSibling
== 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
;
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
;
105 public PairingHeapNode
getChild() {
109 public boolean hasMultipleChildren() {
110 return this.child
!= null && this.child
!= this.child
.nextSibling
;
113 public void setAsRoot() {
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;
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
;
128 this.nextSibling
= this.previousSibling
= this;
132 public String
toString() {
133 return "node " + this.getKey() + " (" + this.getValue() + ")";
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
;
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
);
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
187 * @see net.kezvh.collections.heaps.Heap#reweight(java.lang.Object, java.lang.Object)
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();
198 return node
.setValue(newWeight
);
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
);
206 this.root
= this.merge(this.root
, node
);
211 private PairingHeapNode
merge(final PairingHeapNode a
, final PairingHeapNode b
) {
216 if (a
.compareTo(b
) <= 0) {
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
);
237 if (this.root
== 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)
249 public Iterator
<E
> iterator() {
250 throw new UnimplementedException(); // FIXME
254 public void clear() {
260 public boolean contains(final Object o
) {
261 return this.map
.containsKey(o
);
265 public boolean containsAll(final Collection
<?
> c
) {
266 return this.map
.entrySet().containsAll(c
);
270 public boolean isEmpty() {
271 return this.map
.isEmpty();
277 final E minValue
= this.root
.getKey();
278 this.map
.remove(minValue
);
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.
295 public boolean remove(final Object o
) {
296 throw new UnimplementedException(); // FIXME
301 return this.map
.size();
305 public Comparator
<?
super W
> comparator() {
306 return this.comparator
;