sub debug ($;@) { # Uncomment the next line to see a partial execution trace # print @_; } my @stack = @ARGV; # Initialise the stack with test values push @stack, scalar(@stack); # Push the length quicksort(); # call the sort routine print "Result: @stack\n"; # and print the result sub quicksort { local ($n) = pop(@stack); push @stack, $n; push @stack, 0; sort_and_tuck(); push @stack, $n; } sub sort_and_tuck { local ($w) = pop(@stack); # where to put result local ($c) = pop(@stack); # number of items debug " \$w=$w; \$c=$c; \@stack=@stack\n"; if ($c == 1) { rotate_up($w+1); } elsif ($c > 1) { local ($p) = pop(@stack); # pivot $c--; local ($n) = $c; local ($i) = $c; debug "\t< \$p=$p; \$n=$n"; while ($i--) { local ($e) = pop(@stack); # examine top element push @stack, $e; debug "\t\t\$e=$e (@stack)\n"; if ($p gt $e) { rotate_up($c); -- $n; } else { rotate_up($n); } } debug "\t> \$n=$n\n"; # Now we've partitioned the list. The top $n elements are gt $p, # and the next ($c-$n) are le $p. Sort the partitions. local($r) = $c-$n; push @stack, $n; push @stack, $w+$r; sort_and_tuck(); push @stack, $r; push @stack, $w; sort_and_tuck(); push @stack, $p; # Reinsert the pivot rotate_up(1+$w+$r); debug " Return: @stack\n" } } # Should be called put_away(), but I'm not allowed to modify it ;-) sub rotate_up { local($a,$b); $a=$_[0]; $a--; return if $a<1; $b=pop @stack; splice(@stack, -$a, 0, $b); }