【问题标题】:algorithm binary search return range perl算法二分查找返回范围 perl
【发布时间】:2017-04-03 23:33:06
【问题描述】:

我有一个包含数百万个浮点数(有序)的数组,然后是另一个较小的数组,我需要在一定的公差范围内匹配数字(大数组中的值与小数组)从大数组中的小数组。好吧,没什么大不了的,这是用于在容差范围内返回不完美匹配的 perl 函数,它在 for 循环中,我正在循环遍历小数组值。

sub bin_search{
my ($arr, $v, $t ) = @_;
my ($min, $max) = (0, @$arr-1);
while ($min <= $max) {
  my $w   = $v + $t;
  my $k   = $v - $t;
  my $try = int( ( $min + $max ) / 2 );
  $min    = $try + 1, next if $arr -> [$try] < $k  ;
  $max    = $try - 1, next if $arr -> [$try] > $w ;
  return $arr -> [$try] ;
  }
 return 0;
} 

但是在检查我的数据之后,我似乎丢弃了一些值,因为它只返回第一个匹配项。 我试过 grep 但它太慢了。

 my $min = $val - $t;
 my $max = $val + $t;
 my @arr2 = grep { ( $_ > $min ) && ($_ < $max ) }@big_arr1; 

所以我想稍微修改一下二进制搜索以返回从 $min 到 $max 的范围,因为我认为一旦有一个匹配项是在 $min 或 $max 处,所以类似于

sub bin_search{
my ($arr, $v, $t ) = @_;
my ($min, $max) = (0, @$arr-1);
my $w   = $v + $t;
my $k   = $v - $t;
while ($min <= $max) {
  my $try = int( ( $min + $max ) / 2 );
  $min    = $try + 1, next if $arr -> [$try] < $k  ;
  $max    = $try - 1, next if $arr -> [$try] > $w ;
  last;
  }
 my @fin;
 if ( ($arr -> [$try] < $w) && ($arr -> [$try] > $k) ) {
    push @fin, $arr ->[$try]; $try++ }
 return \@fin;
} 

但是我遗漏了一些价值观,并且我认为我遗漏了一些东西,我当时应该只看一个方向吗?喜欢离开直到我们达到下限然后返回 $try 并做同样的事情直到上限?

【问题讨论】:

  • 那么小数组中的数字可以匹配大数组中的多个数字吗?并且大数组中的数字是按升序排列的,但不一定唯一?
  • 您最多调用一次push @fin
  • @ikegami 是的,应该是错字
  • 1) 不要发布您实际上没有运行的代码。 2)问题是你寻找范围的结尾,但你从来没有寻找它的开始。
  • @HåkonHægland 大数组从低到高排序,它们是唯一值,而小数组一个数字可以匹配到我认为大约在公差范围内的 20 个值(我有 6 个小数点并且公差有 4 所以我认为 20 是匹配数的一个很好的近似值)。

标签: arrays perl search binary


【解决方案1】:

首先使用二分搜索查找匹配元素的索引。

一旦你有了它,你需要找到范围的开始位置。您也可以使用二分搜索,但如果匹配元素的数量通常很少,也可以使用线性搜索。

最后,您需要找到范围的结尾。您可以使用与查找范围起点相同的方法。

您的解决方案的问题是您没有寻找范围的开始。

以下是使用线性扫描方法(如您的)的未经测试的实现,因此它假设匹配元素很少:

sub binsearch_numeric_range {
   my $min   = shift;
   my $max   = shift;
   my $array = shift;

   return () if !@$array;

   my $i = 0;
   my $j = $#$array;

   my $k;
   while (1) {
      $k = int(($i+$j)/2);

      if ($array->[$k] > $max) {
         $j = $k-1;
         return () if $i > $j;
      }
      elsif ($array->[$k] < $min) {
         $i = $k+1;
         return () if $i > $j;
      }
      else {
         last;
      }
   }

   my $min_k = $k;  --$min_k while $min_k > 0        && $array->[$min_k - 1] >= $min;
   my $max_k = $k;  ++$max_k while $max_k < $#$array && $array->[$max_k + 1] <= $max;

   return @$array[$min_k .. $max_k];
}

my @matches = binsearch_numeric_range($v-$t, $v+$t, $arr);

不需要编写全新的binsearch 的实现:

my $idx = binsearch { abs($a-$b) <= $t ? 0 : $a <=> $b } $v, @$arr;

my @range;
if ($idx >= 0) {
   my $min_idx = $idx;  --$min_idx while $min_idx > 0      && $arr->[$min_idx-1] >= ($v-$t);
   my $max_idx = $idx;  ++$max_idx while $max_idx < $#$arr && $arr->[$max_idx+1] <= ($v+$t);

   @range = @$array[$min_idx .. $max_idx];
}

使用的binsearch 定义为here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2020-10-26
    相关资源
    最近更新 更多