Anno said:
I still think that in practice it would pay to keep the heap size down
to k (the number of elements to be extracted). You'd still have to
*inspect* all the input, but the number of "heap operations" (heap
insertions and original (non-recursive) calls to heapify()) would be
much smaller, and operate on a smaller heap.
Anno
Unfortunately, no. I wrote some benchmarks just to see what happens in
practice. The subroutine heap_each() is commented out since it takes so
long to complete.
--- Shawn
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark;
# Un-comment for testing; do forget to un-comment
# the print statements in each suborutine.
# heap_once();
# heap_occasional();
# heap_each();
# sort_once();
# sort_occasional();
# sort_each();
# simple();
# exit;
timethese( 100,
{
simple => \&simple,
heap_once => \&heap_once,
heap_occasional => \&heap_occasional,
# heap_each => \&heap_each,
sort_once => \&sort_once,
sort_occasional => \&sort_occasional,
sort_each => \&sort_each,
},
);
sub heap_once {
my @top = ();
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
my $i = $#top;
my $j = 0;
for(;
{
$j = int( $i / 2 );
if( $top[$j] < $top[$i] ){
( $top[$j] , $top[$i] ) = ( $top[$i] , $top[$j] );
}else{
last;
}
last if $j <= 0;
$i = $j;
}
}
my @list = ();
for my $i ( 0 .. 9 ){
push @list, $top[0];
my $j = 0;
while( $j*2+1 <= $#top ){
if( $j*2+2 <= $#top && $top[$j*2+1] < $top[$j*2+2] ){
$top[$j] = $top[$j*2+2];
$j = $j*2+2;
}else{
$top[$j] = $top[$j*2+1];
$j = $j*2+1;
}
}
$top[$j] = 0;
}
# print "@list\n";
}
sub heap_each {
my @top = ();
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
my $i = $#top;
my $j = 0;
for(;
{
$j = int( $i / 2 );
if( $top[$j] < $top[$i] ){
( $top[$j] , $top[$i] ) = ( $top[$i] , $top[$j] );
}else{
last;
}
last if $j <= 0;
$i = $j;
}
my @list = ();
for my $i ( 0 .. 9 ){
push @list, $top[0];
my $j = 0;
while( $j*2+1 <= $#top ){
if( $j*2+2 <= $#top && $top[$j*2+1] < $top[$j*2+2] ){
$top[$j] = $top[$j*2+2];
$j = $j*2+2;
}else{
$top[$j] = $top[$j*2+1];
$j = $j*2+1;
}
}
$top[$j] = 0;
}
@top = @list;
}
# print "@top\n";
}
sub heap_occasional {
my @top = ();
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
my $i = $#top;
my $j = 0;
for(;
{
$j = int( $i / 2 );
if( $top[$j] < $top[$i] ){
( $top[$j] , $top[$i] ) = ( $top[$i] , $top[$j] );
}else{
last;
}
last if $j <= 0;
$i = $j;
}
if( @top > 1_000 ){ # Change 1_000 to be as large as your memory
can handle
my @list = ();
for my $i ( 0 .. 9 ){
push @list, $top[0];
my $j = 0;
while( $j*2+1 <= $#top ){
if( $j*2+2 <= $#top && $top[$j*2+1] < $top[$j*2+2] ){
$top[$j] = $top[$j*2+2];
$j = $j*2+2;
}else{
$top[$j] = $top[$j*2+1];
$j = $j*2+1;
}
}
$top[$j] = 0;
}
@top = @list;
}
}
my @list = ();
for my $i ( 0 .. 9 ){
push @list, $top[0];
my $j = 0;
while( $j*2+1 <= $#top ){
if( $j*2+2 <= $#top && $top[$j*2+1] < $top[$j*2+2] ){
$top[$j] = $top[$j*2+2];
$j = $j*2+2;
}else{
$top[$j] = $top[$j*2+1];
$j = $j*2+1;
}
}
$top[$j] = 0;
}
# print "@list\n";
}
sub simple {
my @top = ( 0 ) x 10;
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
my $i = -1;
for( $i = $#top; $i >= 0; $i -- ){
if( $top[$i] > $num ){
@top = ( @top[ 0 .. $i ], $num, @top[ $i + 1 .. $#top ] );
pop @top;
last;
}
}
if( $i < 0 ){
unshift @top, $num;
pop @top;
}
}
# print "@top\n";
}
sub sort_each {
my @top = ( 0 ) x 10;
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
@top = sort { $b <=> $a } @top;
$#top = 9;
}
# print "@top\n";
}
sub sort_occasional {
my @top = ( 0 ) x 10;
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
if( @top > 1_000 ){ # Change 1_000 to be as large as your memory
can handle
@top = sort { $b <=> $a } @top;
$#top = 9;
}
}
@top = sort { $b <=> $a } @top;
$#top = 9;
# print "@top\n";
}
sub sort_once {
my @top = ( 0 ) x 10;
srand( 1 );
for my $i ( 1 .. 10_000 ){
my $num = rand();
push @top, $num;
}
@top = sort { $b <=> $a } @top;
$#top = 9;
# print "@top\n";
}
__END__