我想在Perl中實現二進制搜索算法。我的'數組'按降序排列(不是一個實際的數組,而是一個獲取索引並返回值的函數)。問題在於可能存在延伸的相同值。如果我的搜索值處於這樣的範圍內,我想返回包含它的第一個索引。如何在Perl中實現二進制搜索?
這是我寫:
# get_val should be a *decreasing* function for idexes $i in min..max,
# formally: for any $i,$j s.t. $max>=$i>$j>=$min :
# $get_val_subref($i, $extra) <= $get_val_subref($j, $extra)
# min and max are the inclusive boundaries for the search
# get_val sub should get an index in min..max and an extra data reference, and return
# the value for the given index
# returns the smallest index $i in min..max for which $get_val_subref($j, $extra)
# returns $searched_val, or undef if no such index exists
sub binary_search {
my ($min, $max, $searched_val, $get_val_subref, $get_val_sub_extra_data)
= @_;
my ($mid, $val);
while ($min <= $max) {
$mid = $min + int(($max - $min)/2);
$val = $get_val_subref->($mid, $get_val_sub_extra_data);
if ($val > $searched_val) {
$min = $mid + 1;
}
elsif ($val < $searched_val) {
$max = $mid - 1;
}
else { ## SEE MY QUESTION BELOW ##
# surely $val == $searched_val, but is it the first one?
if ( $mid > $min
and $get_val_subref->($mid - 1, $get_val_sub_extra_data)
== $searched_val)
{
# $val == $searched_val and prev($val) == $searched_val
# we have to continue
$max = $mid - 1;
}
else {
# $val == $searched_val and prev($val) != $searched_val
# wer'e done
return $mid;
}
}
}
# $val was not found. return undef
return undef;
}
,這是使用它一個簡單的例子:
sub get_val_sub {
my ($pos, $a) = @_;
my $val = $a->[$pos];
return $val;
}
my @arr = (80, 40, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
say "RET:", binary_search(0, $#arr, 0, \&get_val_sub, \@arr);
的問題是我不知道我還有最後一個(標有## SEE MY QUESTION BELOW ##
)是「漂亮」。有沒有更好的方法來做到這一點?