use vars
qw($VERSION @ISA @EXPORT @EXPORT_OK);
@ISA = qw(Exporter AutoLoader);
# No names available for export.
# Preloaded methods go here.
# el - linkable element, contains user-provided value
# v - user-provided value
################################################# debugging control
# enable/disable debugging output
@_ ?
($debug = shift) : $debug;
# enable/disable validation checks on values
@_ ?
($validate = shift) : $validate;
$width = 2 if $width < 2;
$bar = $corner = ' ' x
$width;
substr($corner,-2,2) = '+-';
hdump
( $ch = $el->{child
},
$l1 . sprintf( $vfmt, $el->{val
}->val),
while( $ch = $ch->{sib
} ) {
hdump
( $ch, $b . $corner, $b . $bar );
for( $el = $$h; $el; $el = $el->{sib
} ) {
hdump
( $el, sprintf( "%02d: ", $el->{degree
}), ' ' );
my $pdeg = $pel->{degree
};
for( $cel = $pel->{child
}; $cel; $cel = $cel->{sib
} ) {
die "degree not decreasing in heap"
unless --$pdeg == $cel->{degree
};
die "heap order not preserved"
unless $pv->cmp($cel->{val
}) <= 0;
die "degree did not decrease to zero"
heapdump
$h if $validate >= 2;
for( ; $el; $el = $el->{sib
} ) {
or die "degree not increasing in list";
################################################# forward declarations
################################################# heap methods
my $class = ref($self) || $self;
die "Method 'heap' required for element on heap"
die "Method 'cmp' required for element on heap"
my $el = $$h or return undef;
while( $el = $el->{sib
} ) {
if $top->cmp($el->{val
}) > 0;
my $mel = $$h or return undef;
# find the heap with the lowest value on it
while( $pred = \
$el->{sib
}, $el = $$pred ) {
if( $top->cmp($el->{val
}) > 0 ) {
# found it, $mpred points to it, $mel is its container, $val is it
# unlink it from the chain
# we're going to return the value from $mel, but all of its children
# must be retained in the heap. Make a second heap with the children
# and then merge the heaps.
$h->absorb_children($mel);
# finally break all of its pointers, so that we won't leave any
# memory loops when we forget about the pointer to $mel
$mel->{p
} = $mel->{child
} = $mel->{sib
} = $mel->{val
} = undef;
*extract_minimum
= \
&extract_top
;
my $anymerge = $el1 && $el2;
if( $el1->{degree
} <= $el2->{degree
} ) {
# advance on h's list, it's already linked
$dest_link = \
$el1->{sib
};
# move next h2 elem to head of h list
$dest_link = \
$el2->{sib
};
# if h ran out first, move rest of h2 onto end
# clean out h2, all of its elements have been move to h
# fix up h - it can have multiple items at the same degree if we
# actually merged two non-empty lists
$anymerge ?
$h->self_union: $h;
# a key has been decreased, it may have to percolate up in its heap
my $el = $v->heap or return undef;
last if $v->cmp($p->{val
}) >= 0;
# to delete an item, we bubble it to the top of its heap (as if its key
# had been decreased to -infinity), and then remove it (as in extract_top)
my $el = $v->heap or return undef;
# bubble it to the top of its heap
# find it on the main list, to remove it and split up the children
for( $p = $h; ($n = $$p) && $n != $el; $p = \
$n->{sib
} ) {
# remove it from the main list
# put any children back onto the main list
$h->absorb_children($el);
################################################# internal utility functions
$ch = $el->{child
} and elem_DESTROY
$ch;
$el->{child
} = $el->{sib
} = $el->{p
} = $el->{val
} = undef;
$el->{sib
} = $p->{child
};
# we've merged two lists in degree order. Traverse the list and link
# together any pairs (adding 1 + 1 to get 10 in binary) to the next
# higher degree. After such a merge, there may be a triple at the
# next degree - skip one and merge the others (adding 1 + 1 + carry
# of 1 to get 11 in binary).
while( $next = $cur->{sib
} ) {
if( $cur->{degree
} != $next->{degree
} ) {
# two or three of same degree, need to do a merge. First though,
# skip over the leading one of there are three (it is the result
# [carry] from the previous merge)
if( ($n2 = $next->{sib
}) && $n2->{degree
} == $cur->{degree
} ) {
if( $cur->{val
}->cmp($next->{val
}) <= 0 ) {
$cur->{sib
} = $next->{sib
};
# we've added one element at the front, keep merging pairs until there isn't
# one of the same degree (change all the low order one bits to zero and the
# lowest order zero bit to one)
while( $next = $cur->{sib
} ) {
return if $cur->{degree
} != $next->{degree
};
if( $cur->{val
}->cmp($next->{val
}) <= 0 ) {
$cur->{sib
} = $next->{sib
};
# absorb all the children of an element into a heap
my $child = $el->{child
};
Heap::Binomial - a Perl extension for keeping data partially sorted
$heap = Heap::Binomial->new;
Keeps elements in heap order using a linked list of binomial trees.
The I<heap> method of an element is used to store a reference to
the node in the list that refers to the element.
See L<Heap> for details on using this module.
John Macdonald, jmm@perlwolf.com
Copyright 1998-2003, O'Reilly & Associates.
This code is distributed under the same copyright terms as perl itself.