如何在Perl中进行整数除法OR如何使二进制搜索工作?

时间:2013-04-10 20:35:07

标签: perl int binary-search

我正在尝试实施二进制搜索。这是我的代码:

#!/usr/bin/perl
#use strict;
use warnings;

@array = (1..100);
$number = <STDIN>;
$low = 0;
$high = $#array;

while($low < $high){
    print "Searcing $low ---- $high \n";
    $mid = $low + ($high - $low)/2;
    if($array[$mid] == $number){
        print "Found in index:" . $mid;
        last;
    }
    elsif($array[$mid] < $number){
        $low = $mid + 1;
    }
    else{
        $high = $mid - 1;
    }   
}

但它不起作用,虽然它是一个简单的实现(至少它将在Java中) 似乎我在划分时得到浮点值并且无法搜索。如果我提供输入5,我会得到垃圾:

5  
Searcing 0 ---- 99  
Searcing 0 ---- 48.5  
Searcing 0 ---- 23.25  
Searcing 0 ---- 10.625  
Searcing 0 ---- 4.3125  
Searcing 3.15625 ---- 4.3125  

如何让它使用整数,以便我可以索引数组?
此外,如果我取消注释use strict,我会收到以下错误。他们的意思是什么?

Global symbol "@array" requires explicit package name at D:\Development\Perl\chapter3\binarySearch.pl line 6.  
Global symbol "$number" requires explicit package name at D:\Development\Perl\chapter3\binarySearch.pl line 9.  
Global symbol "$low" requires explicit package name at 

6 个答案:

答案 0 :(得分:6)

my $int = int 5 / 2;
print $int;

打印2。

答案 1 :(得分:3)

两个深奥的解决方案。除非你真的很无聊或其他什么,否则不要使用这些。

  1. use integer - 一个强制Perl将所有数值视为整数的pragma。它可以是本地范围的,因此它不会破坏程序中的所有数据

    while($low < $high){
        print "Searcing $low ---- $high \n";
        {
            use integer;
            $mid = $low + ($high - $low)/2;
        }
        if($array[$mid] == $number){
            print "Found in index:" . $mid;
            last;
        }
        elsif($array[$mid] < $number){
            $low = $mid + 1;
        }
        else{
            $high = $mid - 1;
        }   
    }
    
  2. Perl有一些特殊变量$=$-$%,它们只保存整数值,无论你赋予它们什么。直接使用它们

    $- = $low + ($high - $low) / 2;
    if ($array[$-] == $number) { ...
    

    或作为中间体

    my $mid = $- = $low + ($high - $low) / 2;
    if ($array[$mid] == $number) { ...
    

    使用这样的魔术变量对于code golf来说很方便,并且会激怒你的同事,但其他的并不多。

答案 2 :(得分:2)

您应该使用int函数。

除此之外,您需要use strict;并使用my来确定变量的范围。这将捕获您可能错过的错误。只需声明它们:

my @array = (1..100);
chomp(my $number = <STDIN>);
my $low = 0;
my $high = $#array;

my $mid = int ($low + ($high - $low)/2);

您也可以考虑使用chomp来删除输入中的换行符。

答案 3 :(得分:2)

使用优质的>> 1代替/2

示例:

perl -e 'BEGIN { print 5/2, " : ", 5>>1}'

输出:

2.5 : 2

并使用(备用减法):

my $mid = ($low + $high) >> 1;

答案 4 :(得分:2)

您的代码存在很多问题。

  • 您已停用strict

    大概是因为下一个问题。

  • 您未使用myour甚至use vars声明任何变量。

    our @array = 1..100;
    use vars qw'$mid $low $high';
    my $number = <STDIN>
    
  • 你太担心溢出了。这不是C.

    如果你的数字会溢出一个整数,它就会变成一个浮点数。

    my $mid = $low + ($high - $low)/2;
    

    应该只是:

    my $mid = ($high + $low)/2;
    
  • 你期望得到一个除法之外的整数。

    my $mid = ($high + $low)/2;
    

    如果你真的想要一个整数,只需使用int

    my $mid = int( ($high + $low)/2 );
    
  • 您没有从$number

    的末尾删除换行符
    chomp($number);
    
  • 你有一个错误。

    while($low < $high){
    

    应该是

    while($low <= $high){
    

    这确实是你的主要问题。

#! /usr/bin/env perl
use strict;
use warnings;

my @array = 1..100;
my $number = <STDIN>;
chomp $number;
my $low = 0;
my $high = $#array;

while($low <= $high){
    my $mid = int( ($high + $low)/2 );
    printf "Searching %2d .. (%2d) .. %2d\n", $low, $mid, $high;
    if($array[$mid] == $number){
        print "Found $number at index mid $mid\n";
        last;
    }elsif($array[$mid] < $number){
        $low = $mid + 1;
    }else{
        $high = $mid - 1;
    }
}

虽然不是真的Perlish。

#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw'first_index';

my @array = 1..100;
my $number = <STDIN>;
chomp $number;

my $index = first_index { $_ == $number } @array;
print "Found $number at index ", $index if $index != -1;

或者更奇怪

#! /usr/bin/env perl
use strict;
use warnings;

my @array = 1..100;
my $number = <STDIN>;
chomp $number;

my $char = join '', map chr, @array;

my $index = index $char, chr $number;
print "Found $number at index $index\n" if $index != -1;

这适用于UV max或(2 ** 72) - 1中较小的数字 在64位版本上是18,446,744,073,709,551,615,在32位版本上是4,294,967,295。

答案 5 :(得分:1)

首先,

my $mid = $low + ($high - $low)/2

可以简化为

my $mid = ($high + $low)/2;

您可以使用int

获取整体部分
my $mid = int( ($high + $low)/2 );

或者你可以利用位移是整数除以2的事实。

my $mid = ($high + $low) >> 1;

另请参阅:Flexible Binary Search Function