【问题标题】:Perl mergesort - array referencePerl 合并排序 - 数组引用
【发布时间】:2014-02-23 22:37:39
【问题描述】:

我试图在 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++;
        }
    }
}

【问题讨论】:

    标签: perl sorting mergesort


    【解决方案1】:

    sub merge 中,您有两个数组引用:$auxref$aref

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

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

    数组

    my @arr = (1, 2, 3, 4);
    $arr[0] = 5;
    push @arr, 6;
    # @arr = (5, 2, 3, 4, 6)
    

    数组引用

    my $arr = [1,2,3];
    $arr->[0] = 5;
    push @$arr, 6;
    # $arr = [5, 2, 3, 4, 6];
    

    数组引用的二维数组

    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);
    

    【讨论】:

    • 您的$auxref[$i] = $aref[$i] 子中仍然有$auxref[$i] = $aref[$i]。所以这实际上是指您在第 4 行定义的数组,而不是您在合并子开始时声明的数组引用。
    • 您的数组引用现在很好。但是,您还有另一个与范围有关的问题:您的潜艇(意外地?)使用的全局范围中有很多变量。例如。 mergemergeSort 都在使用 $mid,我预计这会导致意外结果。
    • 这就是为什么将 subs 放在“main”代码之前和/或将“main”代码放在 curlies 中的原因。
    • 看看mergeSort,你在调用mergeSort之后使用$mid,期望它与调用mergeSort之前的值相同。它没有。将$mid 的声明移动到它所属的位置。
    • my ( $hi, $lo, $mid, $i, $j, $k ) = 0; 应该被删除。其中一些变量从未使用过,而其他变量则声明在错误的位置。
    【解决方案2】:

    以下是完全不依赖引用的merge sort 版本。几乎可以肯定,它的内存效率不如某些原始合并排序算法的预期目标,但它可以完成工作。

    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;
        }
    }
    

    【讨论】:

    • 另外,如果不提 Perl 的内置 sort 从 5.7 开始就是合并排序,那将是我们的疏忽。
    • ...可以使用use sort '_mergesort';强制执行
    • Re“以下是完全不依赖引用的合并排序版本”,您无需为每一级递归复制整个数组以避免处理引用。这是一件坏事,不是一件好事。你不应该为此感到骄傲。我的反对意见不仅是因为这一点,还因为实际上并没有帮助 OP。他正在努力学习;他不是在寻找实现(否则他只会使用内置的sort)。
    • @ikegami 不必要地复制整个数组正是我觉得可以发布这个版本的原因。它展示了一种实现他想要的东西的失败方式(以便他可以学习),但没有提供最有可能的最终解决方案,它可能应该更严格地遵循算法。
    • 在你开始语义游戏之前,你应该重新阅读我所说的“你不必要地为每一级递归复制整个数组以避免处理引用”。最后一部分是关键。避免使用基本工具,因为它们会给你带来问题,这不是一个好的学习方法。同样,两者都不是简单地给出现有的实现而没有任何解释。再多的文字游戏也无法改变这一点。
    猜你喜欢
    • 2019-04-10
    • 2017-03-22
    • 2016-01-01
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    相关资源
    最近更新 更多