挿入ソートを書いてみた
毎日、何か書こうとすると、やっぱネタ切れしちゃうんだけど、
タイミング良くソート期を迎えたので、
マージソートを書くために段階を踏んでみようと思います。
ソートの性質として、安定と不安定なものがあって、
そういうのを説明するためにも、
とりあえず、挿入ソートを実装してみました。
2013/09/07 追記
カンペを見たら間違っていたので、書き直しました。
use strict;
use warnings;
use v5.10;
main();
sub main {
my @data = 1..9;
# シャッフル
my $n = scalar( @data );
for ( 1..100 ) {
my $a = int( rand $n );
my $b = int( rand $n );
@data[$a,$b] = @data[$b,$a];
}
say '';
say join( ', ', @data );
say '';
say "---- start ----\n";
@data = insert_sort( @data );
say "---- end ----\n";
say join( ', ', @data );
}
sub insert_sort {
my @data = @_;
my $cnt = scalar( @data );
for (my $i=1; $i<$cnt; $i++) {
printf( "\$i = %2d\n", $i );
dump_array( \@data, $i );
my $wk = $data[$i];
my $j = $i;
for (; 0<$j; $j--) {
if ( $wk <= $data[$j-1] ) {
last;
}
else {
$data[$j] = $data[$j-1];
dump_array( \@data, ($i + 1), ($j - 1) );
}
}
$data[$j] = $wk;
dump_array( \@data, ($i + 1) );
print "\n";
}
return @data;
}
sub dump_array {
my ( $ary_ref, $sorted_cnt ) = @_;
my $invalid_index = $_[2] // -1;
my $cnt = scalar( @{$ary_ref} );
my $i = 0;
print '[';
for (; $i<$sorted_cnt; $i++) {
print ( ($i == $invalid_index) ? 'x' : $ary_ref->[$i] );
print ', ' if $i < ($sorted_cnt - 1);
}
print ']';
print ' ' if $i < $cnt;
for (; $i<$cnt; $i++) {
print $ary_ref->[$i];
print ', ' if $i < ($cnt - 1);
}
print "\n";
}
実行結果はこんな感じ。
$ perl bbb.pl
5, 9, 3, 1, 2, 7, 6, 4, 8
---- start ----
$i = 1
[5] 9, 3, 1, 2, 7, 6, 4, 8
[x, 5] 3, 1, 2, 7, 6, 4, 8
[9, 5] 3, 1, 2, 7, 6, 4, 8
$i = 2
[9, 5] 3, 1, 2, 7, 6, 4, 8
[9, 5, 3] 1, 2, 7, 6, 4, 8
$i = 3
[9, 5, 3] 1, 2, 7, 6, 4, 8
[9, 5, 3, 1] 2, 7, 6, 4, 8
$i = 4
[9, 5, 3, 1] 2, 7, 6, 4, 8
[9, 5, 3, x, 1] 7, 6, 4, 8
[9, 5, 3, 2, 1] 7, 6, 4, 8
$i = 5
[9, 5, 3, 2, 1] 7, 6, 4, 8
[9, 5, 3, 2, x, 1] 6, 4, 8
[9, 5, 3, x, 2, 1] 6, 4, 8
[9, 5, x, 3, 2, 1] 6, 4, 8
[9, x, 5, 3, 2, 1] 6, 4, 8
[9, 7, 5, 3, 2, 1] 6, 4, 8
$i = 6
[9, 7, 5, 3, 2, 1] 6, 4, 8
[9, 7, 5, 3, 2, x, 1] 4, 8
[9, 7, 5, 3, x, 2, 1] 4, 8
[9, 7, 5, x, 3, 2, 1] 4, 8
[9, 7, x, 5, 3, 2, 1] 4, 8
[9, 7, 6, 5, 3, 2, 1] 4, 8
$i = 7
[9, 7, 6, 5, 3, 2, 1] 4, 8
[9, 7, 6, 5, 3, 2, x, 1] 8
[9, 7, 6, 5, 3, x, 2, 1] 8
[9, 7, 6, 5, x, 3, 2, 1] 8
[9, 7, 6, 5, 4, 3, 2, 1] 8
$i = 8
[9, 7, 6, 5, 4, 3, 2, 1] 8
[9, 7, 6, 5, 4, 3, 2, x, 1]
[9, 7, 6, 5, 4, 3, x, 2, 1]
[9, 7, 6, 5, 4, x, 3, 2, 1]
[9, 7, 6, 5, x, 4, 3, 2, 1]
[9, 7, 6, x, 5, 4, 3, 2, 1]
[9, 7, x, 6, 5, 4, 3, 2, 1]
[9, x, 7, 6, 5, 4, 3, 2, 1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
---- end ----
9, 8, 7, 6, 5, 4, 3, 2, 1
(ここまで追記)
<strong>#if(0) /* ここから間違い */</strong>
use strict;
use warnings;
use v5.10;
main();
sub main {
my @data = 1..9;
# シャッフル
my $n = scalar( @data );
for ( 1..100 ) {
my $a = int( rand $n );
my $b = int( rand $n );
@data[$a,$b] = @data[$b,$a];
}
say '';
say join( ', ', @data );
say '';
say "---- start ----\n";
@data = insert_sort( @data );
say "---- end ----\n";
say join( ', ', @data );
}
sub insert_sort {
my @data = @_;
my $cnt = scalar( @data );
for (my $i=1; $i<$cnt; $i++) {
printf( "\$i = %2d\n", $i );
dump_array( \@data, $i );
for (my $j=0; $j<$i; $j++) {
if ( $data[$j] < $data[$i] ) {
print $data[$j], ' < ', $data[$i], ' ? true.',
" insert ${data[$i]} to \$data[${j}].\n";
my $wk = $data[$i];
for (my $k=$i; $j<$k; $k--) {
$data[$k] = $data[$k-1];
}
$data[$j] = $wk;
last;
}
}
print "\n";
}
return @data;
}
sub dump_array {
my ( $ary_ref, $sorted_cnt ) = @_;
my $cnt = scalar( @{$ary_ref} );
my $i = 0;
print '[';
for (; $i<$sorted_cnt; $i++) {
print $ary_ref->[$i];
print ', ' if $i < ($sorted_cnt - 1);
}
print ']';
print ' ' if $i < $cnt;
for (; $i<$cnt; $i++) {
print $ary_ref->[$i];
print ', ' if $i < ($cnt - 1);
}
print "\n";
}
実行結果はこんな感じ。
$ perl aaa.pl
5, 8, 6, 9, 3, 4, 1, 2, 7
---- start ----
$i = 1
[5] 8, 6, 9, 3, 4, 1, 2, 7
5 < 8 ? true. insert 8 to $data[0].
$i = 2
[8, 5] 6, 9, 3, 4, 1, 2, 7
5 < 6 ? true. insert 6 to $data[1].
$i = 3
[8, 6, 5] 9, 3, 4, 1, 2, 7
8 < 9 ? true. insert 9 to $data[0].
$i = 4
[9, 8, 6, 5] 3, 4, 1, 2, 7
$i = 5
[9, 8, 6, 5, 3] 4, 1, 2, 7
3 < 4 ? true. insert 4 to $data[4].
$i = 6
[9, 8, 6, 5, 4, 3] 1, 2, 7
$i = 7
[9, 8, 6, 5, 4, 3, 1] 2, 7
1 < 2 ? true. insert 2 to $data[6].
$i = 8
[9, 8, 6, 5, 4, 3, 2, 1] 7
6 < 7 ? true. insert 7 to $data[2].
---- end ----
9, 8, 7, 6, 5, 4, 3, 2, 1
シャッフルも実装したので、無駄に行数があるんだけど、
がんばって、ソート後と未ソートのデータが区別できるように表示しました。
<strong>#endif /* ここまで間違い */</strong>
ちなみに、挿入ソートは安定だそうです。
おしまい。
Leave a Comment