[SML 7132] 並び替えの致命傷

AOKI Atsushi aoki @ sra.co.jp
2006年 2月 10日 (金) 14:19:14 JST


SRA先端技術研究所青木です。

先ほど、じゅんのメーリングリストにポストした内容を、SMLへ
も出すことにしました。参考にしていただければ幸いです。アホな
Smalltalker が育ちませんように。

------------------------------------------------------------
R2D2 (AOKI Atsushi)        http://www.sra.co.jp/people/aoki/


青木です。

集まりの並び替えの際に、注意しなければならないことを書きます。
たとえば、次のような簡単なプログラムを例にして説明しましょう。
ある配列を、順序のある集まりへ、と移し替えるものです。

| anArray aCollection |
anArray := #(0 9 1 8 2 7 3 6 4 5).
aCollection := OrderedCollection new.
anArray do: [:each | aCollection add: each].
^aCollection
==> OrderedCollection (0 9 1 8 2 7 3 6 4 5)

移し替える際に、降順(大から小に進む順)にソートしよう(並び
替えよう)として、次のように書くプログラマが多いと思います。
順序のある集まりに換えて、ソートされた集まりを生成し、降順の
ための比較ブロックを指定しておいて、要素を加えてゆくというも
のです。

| anArray aCollection |
anArray := #(0 9 1 8 2 7 3 6 4 5).
aCollection := SortedCollection new.
aCollection sortBlock: [:n1 :n2 | n1 >= n2].
anArray do: [:each | aCollection add: each].
^aCollection
==> SortedCollection (9 8 7 6 5 4 3 2 1 0)

このプログラムコードは、まったく褒められません。VisualWorks
のハイブリッドなクイックソートのアルゴリズムを有効に利用して
いないからです。OrderedCollection を SortedCollection に換え
ればいいじゃん!では済まされないのです。次のように書くべき。

| anArray aCollection |
anArray := #(0 9 1 8 2 7 3 6 4 5).
aCollection := OrderedCollection new.
anArray do: [:each | aCollection add: each].
aCollection := aCollection asSortedCollection: [:n1 :n2 | n1 >= n2].
^aCollection
==> SortedCollection (9 8 7 6 5 4 3 2 1 0)

では、どれぐらいの性能(動作スピード)の差が出るのかを示しま
しょう。乱数ストリームを用いて、10万個の要素を取り出して、
それらの並び替えに要する時間を、ミリ秒単位で測定してみます。

Time millisecondsToRun: [
	| aStream aCollection |
	aStream := Random new.
	aCollection := SortedCollection new: 100000.
	aCollection sortBlock: [:n1 :n2 | n1 >= n2].
	100000 timesRepeat: [aCollection add: aStream next].
	aCollection]
==> 90665 "←約 90 秒、すなわち、1 分 30 秒だよ!"

Time millisecondsToRun: [
	| aStream aCollection |
	aStream := Random new.
	aCollection := OrderedCollection new: 100000.
	100000 timesRepeat: [aCollection add: aStream next].
	aCollection := aCollection asSortedCollection: [:n1 :n2 | n1 >= n2].
	aCollection]
==> 344 "←たった 0.35 秒"

ご覧のように、とんでもない差となります。計算量は要素数の肩に
かかってくるので、指数関数的に増加するのです。プログラムコー
ドの一行の間違いが、動作性能の致命傷であることを、肝に銘じて
プログラミングをするように!

要素の個数が不定であり、それらを随時、並び替えておかなければ
ならいない、という止むを得ない場合を除いて、アホなコードを書
かないように気をつけましょう。ハイブリッドなクイックソートの
アルゴリズムが有効に働くプログラムコードを作ってくださいまし。

------------------------------------------------------------
R2D2 (AOKI Atsushi)        http://www.sra.co.jp/people/aoki/





SML メーリングリストの案内