Heapsort函数的行为与push和unshift相同。(Perl)

Heapsort函数的行为与push和unshift相同。(Perl),perl,sorting,Perl,Sorting,我一直在尝试实现一个堆排序函数,但它按相反的顺序对数组排序。奇怪的是,无论我是使用unshift还是push,元素总是被反转打印 #!/usr/bin/perl -w use 5.014; no warnings 'recursion'; sub heapify{ my $index = pop @_; my $larger; unless ($index > int(@_/2-1)) { my $left = 2 * $index + 1; my $r

我一直在尝试实现一个堆排序函数,但它按相反的顺序对数组排序。奇怪的是,无论我是使用unshift还是push,元素总是被反转打印

#!/usr/bin/perl -w
use 5.014;
no warnings 'recursion';

sub heapify{
  my $index = pop @_;
  my $larger;
  unless ($index > int(@_/2-1))
  {
    my $left  = 2 * $index + 1;
    my $right = 2 * $index + 2;
    if($right < @_ && ($_[$left]<$_[$right]))
    {
      $larger = $right;
    } else {
      $larger = $left;
    }
    if($_[$index] < $_[$larger])
    {
      ($_[$index],$_[$larger]) = 
      ($_[$larger],$_[$index]) ;
      heapify(@_,$larger);
    }
  }

}

sub max_heap{ 
  for(my $i = int(@_/2 -1) ; $i > -1; --$i){
    heapify(@_,$i);
  }

}

sub heapsort{
  return unless @_ > 1 ;
  max_heap(@_);
  my $last = shift(@_);
  heapsort(@_);
  push(@_,$last);
}


my @test = (9,3,13,7,6,78,2);

heapsort(@test);

say "Heapsorted:";
say join("\n",@test);
#/usr/bin/perl-w
使用5.014;
没有“递归”警告;
亚健康{
我的$index=pop@;
我的美元更大;
除非($index>int(@_/2-1))
{
my$left=2*$index+1;
my$right=2*$index+2;
如果($right<@-&($\[$left]-1;--$i){
heapify(@,$i);
}
}
亚堆{
返回,除非@大于1;
最大堆数(@);
我的$last=班次(@u;);
希普索尔(heapsort),;
推送(最后一次);
}
my@test=(9,3,13,7,6,78,2);
heapsort(@test);
说“Heapsorted:”;
说join(“\n”,@test);
已使用

使用严格;
使用警告;
我的@a=反向1..500;
heapSort(\@a);
打印“@a\n”;
亚堆{
我的($a)=;
#输入:长度计数的无序数组
#(在最大堆顺序中首先放置a)
希皮菲(a美元);
my$end=$#$a;#//在使用基于零的数组的语言中,子级是2*i+1和2*i+2
而(完){
#(将堆的根(最大值)与堆的最后一个元素交换)
@$a[$end,0]=@$a[0,$end];#交换(a[end],a[0])
#(将堆的大小减小一,以便前一个最大值
#保持在正确的位置)
$end--;
#(将堆放回最大堆顺序)
siftDown($a,0,$end);
}
}
亚健康{
我的($a)=;
我的$count=@$a;
#(在最后一个父节点的索引中为start分配索引)
my$start=($count-2)/2;
而($start>=0){
#(将索引开始处的节点筛选到适当的位置,以便下面的所有节点
#开始索引按堆顺序排列)
siftDown($a,$start,$count-1);
$start--;
#(筛选根目录后,所有节点/元素都按堆顺序排列)
}
}
亚稳态{
我的($a,$start,$end)=@;
#input:end表示堆向下的距离限制
#筛选。
我的$root=$start;
而($root*2+1[$swap]<$a->[$child];
#(检查是否存在正确的子项,以及它是否大于我们当前交换的子项)
$swap=$child+1,如果$child+1[$swap]<$a->[$child+1];
#(检查我们是否需要交换)
如果($swap!=$root){
#交换(一个[根],一个[交换])
@$a[$root,$swap]=@$a[$swap,$root];
$root=$swap;#(现在重复以继续筛选子级)
}
否则{
返回;
}
}
}

这是指2013年12月31日17时46分由Сааа27回答的所需代码变更

当输入数组的元素数为偶数n时,代码工作正常,但当n为奇数时,代码出错

对于像
@a=qw(10 11 2);

输出将为
=2110

输出错误,因为在第一步中,上面的脚本跳过了对最后一个父项的左子项的检查。当左项较大时,该子项不会与其父项交换

解决方法很简单:

 my $start = int(($count - 2 ) / 2);

如果你关心速度,为什么不让perl来做排序呢?我真的不关心速度。我只是想学习如何正确实现算法,似乎我做错了什么,因为对1000个元素的数组进行排序需要30-40秒。无法复制,这段代码对我来说非常快:但那是因为它甚至没有编译。你介意尽你所能修复你的错误吗?(例如,
for
需要一个块,而不仅仅是一个语句)我的错误,这是最后一分钟的更改,我忘了修复它。你现在可以复制吗?我会尝试传递数组引用,即
heapify($aref,$I);
而不是数组,加上数组赋值
@=heapify(@,$i)
这不是维基百科上的算法吗?@Veritas是的,你有上面的链接。它使用数组引用,速度更快。是的,但它将所有内容按相反顺序排序。奇怪的是,它对取消移位和推送都有相同的操作。
@=reverse@
作为
heapsort()中的最后一行
很明显,这是一个修复方法,但我更希望知道是什么原因造成的。其工作原理是,它创建一个堆,删除第一个重复(递归)的元素,然后将删除的元素推到最后。至少它应该这样做。
 my $start = int(($count - 2 ) / 2);