我一直在尝试实现堆排序功能,但它以相反的顺序对数组进行排序。奇怪的是,如果我使用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);
答案 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);