Bucket Sort & Distribution Counting Sort
まぁ、データの特性が利用できるならO(n log n)より速いアルゴリズムが存在するのは、その道の人には常識だったりもするが。
sub bucket_sort(\@&){ my ($aref, $cref) = @_; my @bucket = (); $bucket[$_] = $_ for (@$aref); my $i = 0; defined $_ and $aref->[$i++] = $_ for (@bucket); return $aref; }
うぇ、重複値があると要素が消失しちゃう。広義にはこういうのも bucket sort だけど、重複を許さないとかなりアプリケーションが限定されるような。弾さんも認識してて説明してないだけなんだろうけど。
sub bucket_sort { my ($array) = @_; my @bucket = (); for (@$array) { if (defined $bucket[$_]) { push @{$bucket[$_]}, $_; } else { $bucket[$_] = [$_]; } } my @out; defined $_ and splice @out, @out, @$_, @$_ for @bucket; return \@out; }
インターフェースが変わっているけど、こんな感じに bucket の要素を配列/リストにするのが多いんじゃないかなぁ。
自分は分布数えソート(Distribution Counting Sort)を使ったりする。こんなの。
sub dist_sort { my ($aref) = @_; my @count = (); $count[$_]++ for (@$aref); my $sum = 0; for my $i (0..@count-1) { my $t = $count[$i] || 0; $count[$i] = $sum; $sum += $t; } my @out; $out[$count[$_]++] = $_ for @$aref; return \@out; }
一応簡単に手順解説。
ちなみに、Suffix Array を高速に構築するアルゴリズムなんかでは先頭の1、2文字をキーにソートするステップがあったりするんだが、そこではこれらのソートアルゴリズムが使われてたりする。
あと、文字列を対象とする場合は MSD Radix Sort (これも 内部では bucket sort も使うらしい) が速いとか、比較キーが複数ある場合(文字列ソート含む)は Multikey Quicksort が速いとかそういう話もあって非汎用ソートも結構奥が深い。