Algorithm-SkipList
view release on metacpan or search on metacpan
lib/Algorithm/SkipList.pm view on Meta::CPAN
else {
$last_index = $index;
$node = undef;
}
$node ||= $self->_first_node;
unless ($node) {
return;
}
while ($node && $index--) {
$node = $node->header()->[0];
}
$self->last_key( $node, $last_index );
return $node;
}
sub key_by_index {
my ($self, $index) = @_;
my $node = $self->_node_by_index($index);
if ($node) {
return $node->key;
} else {
return;
}
}
sub value_by_index {
my ($self, $index) = @_;
my $node = $self->_node_by_index($index);
if ($node) {
return $node->value;
} else {
return;
}
}
sub index_by_key {
my ($self, $key) = @_;
my $node = $self->_first_node;
my $index = 0;
while ($node && ($node->key_cmp($key) < 0)) {
$node = $node->header()->[0];
$index++;
}
if ($node->key_cmp($key) == 0) {
$self->last_key( $node, $index );
return $index;
} else {
return;
}
}
sub _debug {
my $self = shift;
my $list = $self->list;
while ($list) {
print STDERR
$list->key||'undef', "=", $list->value||'undef'," ", $list,"\n";
for(my $i=0; $i<$list->level; $i++) {
print STDERR " ", $i," ", $list->header()->[$i]
|| 'undef', "\n";
}
# print STDERR " P ", $list->prev() || 'undef', "\n";
print STDERR "\n";
$list = $list->header()->[0];
}
}
=head1 NAME
Algorithm::SkipList - Perl implementation of skip lists
=head1 REQUIREMENTS
The following non-standard modules are used:
enum
=head1 SYNOPSIS
my $list = new Algorithm::SkipList();
$list->insert( 'key1', 'value' );
$list->insert( 'key2', 'another value' );
$value = $list->find('key2');
$list->delete('key1');
=head1 DESCRIPTION
This is an implementation of I<skip lists> in Perl.
Skip lists are similar to linked lists, except that they have random
links at various I<levels> that allow searches to skip over sections
of the list, like so:
4 +---------------------------> +----------------------> +
| | |
3 +------------> +------------> +-------> +-------> +--> +
| | | | | |
2 +-------> +--> +-------> +--> +--> +--> +-------> +--> +
| | | | | | | | |
1 +--> +--> +--> +--> +--> +--> +--> +--> +--> +--> +--> +
A B C D E F G H I J NIL
A search would start at the top level: if the link to the right
lib/Algorithm/SkipList.pm view on Meta::CPAN
This is an internal function for generating a random level for new nodes.
Levels are determined by the L<P|/"p"> value. The probability that a
node will have 1 level is I<P>; the probability that a node will have
2 levels is I<P^2>; the probability that a node will have 3 levels is
I<P^3>, et cetera.
The value will never be greater than L</max_level>.
Note: in earlier versions it was called C<_random_level>.
=item list
$node = $list->list;
Returns the initial node in the list, which is a
C<Algorithm::SkipList::Node> (See L<below|/"Node Methods">.)
The key and value for this node are undefined.
=item _first_node
$node = $list->_first_node;
Returns the first node with a key (the second node) in a list. This
is used by the L</first_key>, L</least>, L</append> and L</merge>
methods.
=item _greatest_node
$node = $list->_greatest_node;
Returns the last node in the list. This is used by the L</append> and
L</greatest> methods.
=item _node_class
$node_class_name = $list->_node_class;
Returns the name of the node class used. By default this is the
C<Algorithm::SkipList::Node>, which is discussed below.
=item _build_distribution
$list->_build_distribution;
Rebuilds the probability distribution array C<{P_LEVELS}> upon calls
to L</_set_p> and L</_set_k>.
=item _set_node_class
=item _set_max_level
=item _set_p
=item _set_k
These methods are used during initialization of the object.
=item _debug
$list->_debug;
Used for debugging skip lists by developer. The output of this
function is subject to change.
=back
=head2 Node Methods
Methods for the L<Algorithm::SkipList::Node> object are documented in
that module. They are for internal use by the main
C<Algorithm::SkipList> module.
=head1 SPECIAL FEATURES
=head2 Tied Hashes
Hashes can be tied to C<Algorithm::SkipList> objects:
tie %hash, 'Algorithm::SkipList';
$hash{'foo'} = 'bar';
$list = tied %hash;
print $list->find('foo'); # returns bar
See the L<perltie> manpage for more information.
=head2 Customizing the Node Class
The default node may not handle specialized data types. To define
your own custom class, you need to derive a child class from
C<Algorithm::SkipList::Node>.
Below is an example of a node which redefines the default type to use
numeric instead of string comparisons:
package NumericNode;
our @ISA = qw( Algorithm::SkipList::Node );
sub key_cmp {
my $self = shift;
my $left = $self->key; # node key
my $right = shift; # value to compare the node key with
unless ($self->validate_key($right)) {
die "Invalid key: \'$right\'"; }
return ($left <=> $right);
}
sub validate_key {
my $self = shift;
my $key = shift;
return ($key =~ s/\-?\d+(\.\d+)?$/); # test if key is numeric
}
To use this, we say simply
$number_list = new Algorithm::SkipList( node_class => 'NumericNode' );
This skip list should work normally, except that the keys must be
( run in 0.438 second using v1.01-cache-2.11-cpan-119454b85a5 )