使用push和unshift,Heapsort函数的行为相同。(Perl)

时间:2013-12-31 13:14:31

标签: 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 $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);

2 个答案:

答案 0 :(得分:1)

已使用pseudocode

use strict;
use warnings;

my @a = reverse 1..500;
heapSort(\@a);
print "@a\n";

sub heapSort {
    my ($a) = @_;
    # input:  an unordered array a of length count

    # (first place a in max-heap order)
    heapify($a);

    my $end = $#$a; # //in languages with zero-based arrays the children are 2*i+1 and 2*i+2
    while ($end) {
        # (swap the root(maximum value) of the heap with the last element of the heap)
        @$a[$end, 0] = @$a[0, $end]; # swap(a[end], a[0])
        # (decrease the size of the heap by one so that the previous max value will
        # stay in its proper placement) 
        $end--;
        # (put the heap back in max-heap order)
        siftDown($a, 0, $end);
    }
}
sub heapify {
    my ($a) = @_;
    my $count = @$a;
    # (start is assigned the index in a of the last parent node)
    my $start = ($count - 2 ) / 2;

    while ($start >= 0) {
        #(sift down the node at index start to the proper place such that all nodes below
        # the start index are in heap order)
        siftDown($a, $start, $count-1);
        $start--;
        #(after sifting down the root all nodes/elements are in heap order)
    }
}
sub siftDown {
     my ($a, $start, $end) = @_;
     # input:  end represents the limit of how far down the heap
     #              to sift.
     my $root = $start;

     while ($root * 2 + 1 <= $end) { # (While the root has at least one child)
        my $child = $root * 2 + 1; # (root*2 + 1 points to the left child)
        my $swap = $root;          # (keeps track of child to swap with)
        #(check if root is smaller than left child)
        $swap = $child if $a->[$swap] < $a->[$child];

        #(check if right child exists, and if it's bigger than what we're currently swapping with)
        $swap = $child + 1 if $child+1 <= $end and $a->[$swap] < $a->[$child+1];

        # (check if we need to swap at all)
        if ($swap != $root) {
            # swap(a[root], a[swap])
            @$a[$root, $swap] = @$a[$swap, $root];
            $root = $swap; # (repeat to continue sifting down the child now)
        }
        else {
            return;
        }
     }
}

答案 1 :(得分:0)

这是提及Сухой27在2013年12月31日17:46回复所需的代码更改。

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

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

之类的输入

输出为= 2 11 10

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

修复很简单:

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