Perl合并排序-数组引用

Perl合并排序-数组引用,perl,sorting,mergesort,Perl,Sorting,Mergesort,我试图在Perl中实现合并排序,我对Perl非常陌生,我知道我在数组引用方面做了一些错误的事情。处理完成后,数组最终会保存相同的值。请帮忙,因为我看不出我错在哪里 更正后的代码: use strict; use warnings; my ( @aref, @auxref ) = (); my ( $hi, $lo, $i, $j, $k, $n ) = 0; @aref = ( 5, 7, 6, 3, 4, 1, 8, 9, 4 ); $n = @aref; mergeSort( \@are

我试图在Perl中实现合并排序,我对Perl非常陌生,我知道我在数组引用方面做了一些错误的事情。处理完成后,数组最终会保存相同的值。请帮忙,因为我看不出我错在哪里

更正后的代码:

use strict;
use warnings;
my ( @aref, @auxref ) = ();
my ( $hi, $lo, $i, $j, $k, $n ) = 0;

@aref = ( 5, 7, 6, 3, 4, 1, 8, 9, 4 );
$n = @aref;

mergeSort( \@aref, \@auxref, 0, $n - 1 );

print "@auxref\n";
print "@aref\n";

sub mergeSort {

    my ($aref)   = $_[0];
    my ($auxref) = $_[1];
    my $lo       = $_[2];
    my $hi       = $_[3];

    if ( $hi <= $lo ) { return; }
    my $mid = 0;
    $mid = int( $lo + ( $hi - $lo ) / 2 );
    mergeSort( $aref, $auxref, $lo,      $mid );
    mergeSort( $aref, $auxref, $mid + 1, $hi );

    merge( $aref, $auxref, $lo, $mid, $hi );

}

sub merge {

    my ($aref)   = $_[0];
    my ($auxref) = $_[1];
    my $lo       = $_[2];
    my $mid      = $_[3];
    my $hi       = $_[4];

    for ( $i = $lo ; $i <= $hi ; $i++ ) {
        $auxref->[$i] = $aref->[$i];
    }

    $i = $lo;
    $j = $mid + 1;

    for ( $k = $lo ; $k <= $hi ; $k++ ) {
        if ( $i > $mid ) {
            $aref->[$k] = $auxref->[$j];
            $j++;
        }
        elsif ( $j > $hi ) {
            $aref->[$k] = $auxref->[$i];
            $i++;
        }
        elsif ( $auxref->[$i] <= $auxref->[$j] ) {
            $aref->[$k] = $auxref->[$i];
            $i++;
        }
        else {
            $aref->[$k] = $auxref->[$j];
            $j++;
        }
    }
}
使用严格;
使用警告;
我的(@aref,@auxref)=();
我的($hi,$lo,$i,$j,$k,$n)=0;
@aref=(5,7,6,3,4,1,8,9,4);
$n=@aref;
合并排序(\@aref,\@auxref,0,$n-1);
打印“@auxref\n”;
打印“@aref\n”;
子合并排序{
my($aref)=$\u0;
my($auxref)=$\u1;
my$lo=$[2];
我的$hi=$[3];
如果($hi[$i];
}
$i=$lo;
$j=$mid+1;
对于($k=$lo;$k$mid){
$aref->[$k]=$auxref->[$j];
$j++;
}
elsif($j>$hi){
$aref->[$k]=$auxref->[$i];
$i++;
}
elsif($auxref->[$i][$j]){
$aref->[$k]=$auxref->[$i];
$i++;
}
否则{
$aref->[$k]=$auxref->[$j];
$j++;
}
}
}

子合并
中,有两个数组引用:
$auxref
$aref

您正在访问数组元素,就像它们是普通数组一样(即,
$aref[0]
),但由于它们是数组引用,您需要首先用箭头解除引用:
$aref->[0]

use strict;
use warnings;
添加到脚本顶部应该可以消除这些错误

阵列

数组引用

数组引用的二维数组

数组引用的2D arrayref

阵列的二维阵列

…无法存在,因为数组只能包含标量

my @arr = ((1, 2), (3, 4));
# @arr = (1, 2, 3, 4);

下面是一个完全不依赖引用的版本。几乎可以肯定,它的内存效率不如某些原始合并排序算法预期的那样高,但它完成了任务

use strict;
use warnings;

my @array = ( 5, 7, 6, 3, 4, 1, 8, 9, 4 );

my @sorted = mergeSort(@array);

print "@sorted\n";

sub mergeSort {
    my @array = @_;

    if (@array > 1) {
        my $mid = int(@array / 2);

        my @lowArray = mergeSort(@array[0..$mid-1]);
        my @highArray = mergeSort(@array[$mid..$#array]);

        # Merge the two halves      
        my @newArray = ();
        while (@lowArray && @highArray) {
            if ($lowArray[0] < $highArray[0]) {
                push @newArray, shift @lowArray;
            } else {
                push @newArray, shift @highArray;
            }
        }

        # Either the low or high array will be empty at this point,
        # so no need to compare for the remainder.
        return (@newArray, @lowArray, @highArray);

    } else {
        return @array;
    }
}
使用严格;
使用警告;
my@array=(5,7,6,3,4,1,8,9,4);
my@sorted=mergeSort(@array);
打印“@sorted\n”;
子合并排序{
我的@array=@;
如果(@array>1){
我的$mid=int(@array/2);
my@lowArray=mergeSort(@array[0..$mid-1]);
my@highArray=mergeSort(@array[$mid..$#array]);
#合并两半
我的@newArray=();
而(@lowArray&&@highArray){
如果($lowArray[0]<$highArray[0]){
推@newArray,移位@lowArray;
}否则{
按@newArray,shift@highArray;
}
}
#此时,低位或高位数组将为空,
#因此,无需对其余部分进行比较。
返回(@newArray、@lowArray、@highArray);
}否则{
返回@array;
}
}

您仍然有
$auxref[$i]=$aref[$i]
在您的
merge
sub中。因此,这实际上指的是您在第4行定义的数组,而不是您在merge sub开头声明的数组引用。您的数组引用现在很好。但是,与作用域相关的另一个问题是:您的sub所在的全局范围中有很多变量(意外地?)使用。例如,
merge
mergeSort
都使用了
$mid
,我认为这会导致意外的结果。这就是为什么将subs放在“main”代码之前和/或放在“main”之前的原因在卷发中编码。查看
mergeSort
,调用
mergeSort
后使用
$mid
,希望它与调用
mergeSort
前具有相同的值。它没有。将
$mid
的声明移动到它所属的位置。
my($hi,$lo,$mid,$i,$j,$k)=0;
应该删除。其中一些变量从未使用过,而其他变量声明在错误的位置。此外,我们不必提及Perl内置的
sort
自5.7以来一直是一种合并排序……可以使用
使用sort'\u mergesort';
重新执行“以下是一个完全不依赖引用的合并排序版本“,你不需要为每一级递归复制整个数组来避免处理引用。这是一件坏事,不是好事。你不应该为此感到骄傲。我的反对票不仅是因为这一点,而是因为没有真正帮助OP。他在努力学习;他不是在寻找实现。”(否则他只会使用内置的
排序
)@ikegami不必要地复制整个数组正是我发布这个版本的原因。它展示了一种实现他想要的东西的完美方式(这样他就可以学习),但没有提供最有可能的最终解决方案,该解决方案可能应该更严格地遵循算法。在开始语义游戏之前,您应该重新阅读我所说的“您不必要地复制每个递归级别的整个数组,以避免处理引用。”最后一部分是关键。避免使用基本工具,因为它们会给您带来问题,这不是一个好的学习方法。再说一遍,也不是简单地给出一个现有的实现,而不做任何解释。再多的文字游戏也无法改变这一点。
my @arr = ([1, 2], [3, 4]);
print $arr[0][1]; # identical to $arr[0]->[1];
push @{$arr[1]}, 5;
# @arr = ([1, 2], [3, 4, 5]);
my $arr = [[1, 2], [3, 4]];
print $arr->[0][1]; # identical to $arr->[0]->[1];
push @{$arr->[1]}, 5;
# $arr = [[1, 2], [3, 4, 5]];
my @arr = ((1, 2), (3, 4));
# @arr = (1, 2, 3, 4);
use strict;
use warnings;

my @array = ( 5, 7, 6, 3, 4, 1, 8, 9, 4 );

my @sorted = mergeSort(@array);

print "@sorted\n";

sub mergeSort {
    my @array = @_;

    if (@array > 1) {
        my $mid = int(@array / 2);

        my @lowArray = mergeSort(@array[0..$mid-1]);
        my @highArray = mergeSort(@array[$mid..$#array]);

        # Merge the two halves      
        my @newArray = ();
        while (@lowArray && @highArray) {
            if ($lowArray[0] < $highArray[0]) {
                push @newArray, shift @lowArray;
            } else {
                push @newArray, shift @highArray;
            }
        }

        # Either the low or high array will be empty at this point,
        # so no need to compare for the remainder.
        return (@newArray, @lowArray, @highArray);

    } else {
        return @array;
    }
}