二进制搜索 - 当使用严格的引用时,不能使用字符串“1”作为符号引用

时间:2016-03-06 18:07:09

标签: perl binary-search

我一直在浏览有关此错误消息的已回答的问题。

我正在尝试解决使用二进制搜索查找某些索引的Rosalind web site中的问题。

当我的子程序找到它似乎忽略它的数字时,如果我尝试打印$found变量,它会给我错误

  

使用严格的参考时,不能使用字符串“1”作为符号引用

代码是这个

sub binarysearch
{
  my $numbertolook = shift;
  my @intarray=@_;
  my $lengthint = scalar @intarray;
  my @sorted = sort {$a <=> $b} @intarray;
  #print $numbertolook, " " , @sorted, "\n";
  my $low=0;
  my $high=$lengthint-1;
  my $found =undef;
  my $midpoint;
     while ($low<$high)
     {
     $midpoint=int(($low+$high)/2);
     #print $midpoint, " ",$low," ", $high, " ", @sorted, "\n";
        if ($numbertolook<$sorted[$midpoint])
        {
            $high=$midpoint;
        }
        elsif ($numbertolook>$sorted[$midpoint])
        {
           $low=$midpoint;
        }
        elsif ($numbertolook==$sorted[$midpoint])
        {
           $found=1;
           print $found "\n";
           last;
        }
        if ($low==$high-1 and $low==$midpoint)
        {
            if ($numbertolook==$sorted[$high])
            {
                $found=1;
                print $found "\n";
                last;
            }
            $low=$high;
        }

     }

  return $found;

} 

3 个答案:

答案 0 :(得分:3)

你想要

print $found, "\n";

或者

print $found . "\n";

$ found和换行符之间没有运算符,它认为$ found是打印换行符的文件句柄,并且因为它不是文件句柄而收到错误。

答案 1 :(得分:1)

如果使用空格分隔调用多个参数调用print,则第一个参数应为文件句柄。这是documentationprint FILEHANDLE LIST

print $found "\n";

您要做的就是与,分开,将其称为print LIST

print $found, "\n";

或以字符串形式连接,也称为print LIST,但LIST只有一个元素。

print $found . "\n";

答案 2 :(得分:1)

我会尽力帮助

首先,尽管看起来很简单,但二进制搜索很难正确编码。主要原因是它是一个一个一个错误的温床,它是如此普遍,以至于它们有自己的Wikipedia page

问题在于,包含值AZ的数组将包含26个元素,索引为0到25.我认为FORTRAN的趋势和Lua,但几乎每个其他语言在索引零处具有数组的第一个元素

在您开始使用divide and conquer algorithms之前,零基础适用于所有内容。合并排序以及二进制搜索都是这样的算法。二进制搜索

  • 是上半场吗?
  • 如果是,那么进一步搜索上半部分
  • 进一步搜索下半场

困难的部分是当你必须决定何时找到了这个物体,或者当你需要放弃寻找时。将数据分成两半几乎很容易。知道何时停止 hard

它对排序数据非常有效,但实现它时会出现问题,如果我们正确地执行它,我们必须处理超过零或一的所有类型的奇怪索引库。

假设我有一个数组

my @alpha = 'A' .. 'Q'

如果我print scalar @alpha我会看到17,这意味着数组有17个元素,索引从0到16

现在我在那个数组中寻找E,所以我进行二分搜索,所以我想要&#34;前半部分&#34;和#34;下半场&#34; @alpha。如果我添加0到16并除以2,我得到一个整洁的&#34; 8&#34;,所以中间元素位于索引8,即H

但是等等。有17个元素,这是一个奇数,所以如果我们说前八个(A .. H)留在中间和后八个(I .. { {1}})正好在中间,然后肯定是&#34;中间&#34;是Q

事实上,这完全是一种欺骗,因为二进制搜索会起作用,但我们会对数据进行分区。在这种情况下,二进制意味着两个部分,虽然如果这些部分的大小相等,搜索会更有效,但算法不需要工作。所以它可以是前三分之一和后三分之二,或者只是第一个元素和其余元素

这就是使用I的原因。它向下舍入到最接近的整数,以便我们的17个元素数组int(($low+high)/2)是可用的8而不是8.5

但是你的代码仍然要考虑一些意想不到的事情。在我们的17元素数组的情况下,我们计算出中间索引为8.因此索引0 .. 7是&#34;前半部分&#34;而8 ... 16是&#34;下半场&#34;,中间指数是下半场开始的地方

但我们没有围绕向下分区?因此,在奇数个元素的情况下,我们的中点不应该在上半部分的末尾,而不是第二个的开始?这是一个神秘的一个一个错误,但让我们看看它是否仍适用于简单的偶数个元素

$mid

开头和和索引是0和3;中间索引是@alpha = `A` .. `D` == 1.所以前半部分是0..1而下半部分是2 .. 3.工作正常

但还有更多。假设我必须使用两个元素int((0+3)/2)X搜索数组。这有两个明显的一半,我正在寻找Y,这是在中间之前。所以我现在搜索A的单元素列表X。目标数组的最小和最大元素都为零。中点是A == 0.那么接下来会发生什么?

当我们在同一个列表中搜索int((0+0)/2)时,情况类似但更糟糕。代码必须完全正确,否则我们将搜索数组的末尾或一次又一次地检查最后一个元素

最后保存最差,假设

Z

我正在寻找my @alpha = ( 'A', 'B, 'Y, 'Z' ) 。这样可以避免涉及检查的各种优化,这可能会使普通情况慢得多

由于所有这一切,它是使用库或语言内置函数来完成所有这些工作的最佳解决方案。特别是,Perl的哈希通常是检查特定字符串和任何相关数据所需的全部内容。使用的算法比任何非平凡数据集的二进制搜索要好得多。

维基百科显示this algorithm进行迭代二元搜索

  

二进制搜索算法也可以用两个索引限制迭代表示,这两个索引限制会逐渐缩小搜索范围。

M

这是您的代码版本,它远非无错误,但可以实现您的目标。你离这么远了

   int binary_search(int A[], int key, int imin, int imax)
   {
     // continue searching while [imin,imax] is not empty
     while (imin <= imax)
       {
         // calculate the midpoint for roughly equal partition
         int imid = midpoint(imin, imax);
         if (A[imid] == key)
           // key found at index imid
           return imid;
         // determine which subarray to search
         else if (A[imid] < key)
           // change min index to search upper subarray
           imin = imid + 1;
         else        
           // change max index to search lower subarray
           imax = imid - 1;
       }
     // key was not found
     return KEY_NOT_FOUND;
   }

输出

use strict;
use warnings 'all';

print binarysearch( 76, 10 .. 99 ), "\n";

sub binarysearch {

    my $numbertolook = shift;
    my @intarray     = @_;
    my $lengthint    = scalar @intarray;
    my @sorted       = sort { $a <=> $b } @intarray;

    my $low   = 0;
    my $high  = $lengthint - 1;
    my $found = undef;
    my $midpoint;

    while ( $low < $high ) {
        $midpoint = int( ( $low + $high ) / 2 );

        #print $midpoint, " ",$low," ", $high, " ", @sorted, "\n";
        if ( $numbertolook < $sorted[$midpoint] ) {
            $high = $midpoint;
        }
        elsif ( $numbertolook > $sorted[$midpoint] ) {
            $low = $midpoint;
        }
        elsif ( $numbertolook == $sorted[$midpoint] ) {
            $found = 1;
            print "FOUND\n";
            return $midpoint;
        }

        if ( $low == $high - 1 and $low == $midpoint ) {
            if ( $numbertolook == $sorted[$high] ) {
                $found = 1;
                print "FOUND\n";
                return $midpoint;
            }
            return;
        }

    }

    return $midpoint;
}