VB6 に適したソート

一言で説明すれば、コムソートって VB6 にすごく適したソートアルゴリズムなんじゃない?ってこと。追記: 訂正記事があるので読んでね。

uBMplay は仕様上読み込んだオブジェをソートする必要があるので、そのためにクイックソートを使っているのだけど、先日デバッグをしていて、いくらなんでも遅すぎることに気がついた。

知っている人も多いと思うが、VB6 は C 言語と違ってクイックソートがデフォルトで用意されていない。そのため自前でコードを書かないといけないのだけど、なんと過去の自分はここで横着をして、ネット上から適当なコードを拾って使っていたのだ。そのコードをよく見てみると、"一般的な" クイックソートの実装から少しずれていることに気がついた (以降、クイックソートもどきと呼ぶ)。そこで "一般的な" クイックソートに書き直してテストしてみたところ、クイックソートもどきとは比較にならないほど速くなった。

・・・ところが、ここで問題が発生。一部を除き、ほとんどの BMS ではスタックオーバーフローが起きて強制終了してしまうという事態に。驚くべきことに、過去にコピペしたクイックソートもどきは、速度を犠牲にしてこれを回避したコードだったのだ (多分)!THE 勘違い

さすがに強制終了してしまうのを放置するわけにもいかず、とはいえクイックソートもどきは速度に難がある。なら他のソートアルゴリズムを探そうか、と Wikipedia のソートの項目を見てみたところ、コムソートという聞き慣れないものを発見。詳しく見てみると、平均計算時間は O(n log n) と優秀で、しかも再帰が必要ない。早速テストしてみた結果、速度こそクイックソートに比べれば劣るものの、クイックソートもどきとはまだ比較にならないほど速いし、何よりスタック領域が不足することが絶対にない。というわけでコムソートを採用することに決定。

で、このコムソートって、実は VB6 にすごく適したソートアルゴリズムなんじゃないかな、と思った。再帰を使わないので安全だし、コードもシンプル、そして十分な速度もある (最速というわけではないけど、VB6 って時点で極端な高速化は諦めているようなものだし)。欠点は・・・知名度が低すぎる、くらいかな。ソートで検索すると上位に出てくるソートアルゴリズムを比較するサイトには載っていないし、ヒット数もクイックソートの40万件弱に対してコムソートの900件弱はあまりにも悲惨。というわけで、みんなでバンバン使って知名度を上げていきましょう。ご一緒に VB6 もいかがですか?

最後に uBMplay の話に戻るけど、まだ修正すべき部分が多々あるのと、追加・変更した部分のデバッグが済んでいないのでリリースはまだまだ先になります。気長にお待ちください。

おまけ: 特に書く必要もないと思うけどコード。Swap は二つの変数の中身を交換する関数。途中にあるコメントの入った行はコムソート11のための判定行。この行をコメントアウトすれば普通のコムソートになります。

Public Sub CombSort(ByRef array() As Variant)

    Dim i       As Long
    Dim gap     As Long
    Dim max     As Long
    Dim flag    As Long
    
    gap = Int(UBound(array) / 1.3)
    
    Do
    
        If gap < 1 Then gap = 1
        If gap = 9 Or gap = 10 Then gap = 11 'Comb Sort 11
        
        flag = 0
        max = UBound(array) - gap
        
        For i = 0 To max
        
            If array(i) > array(i + gap) Then
            
                Call Swap(array(i), array(i + gap))
                flag = i
            
            End If
        
        Next i
        
        gap = Int(gap / 1.3)
    
    Loop While (gap > 0 Or flag <> 0)

End Sub