Sub Test1()
t = Timer
Dim A, B
'データを取得
A = Range("A2:A100001")
'バブルソート
For i = 1 To UBound(A, 1) - 1
For j = i + 1 To UBound(A, 1)
If A(i, 1) > A(j, 1) Then
B = A(i, 1)
A(i, 1) = A(j, 1)
A(j, 1) = B
End If
Next
Next
'データを貼り付け
Range("C2").Resize(UBound(A, 1)) = A
Debug.Print Timer - t & " 秒"
End Sub
このようにVBAコードは比較的簡単にかけます。
では、VBAコードを実行してみます。
配列は、あらかじめセルに入力した値から作成します。
10万行のデータを入力しています。
バブルソートで昇順にソートした結果を、セルに入力します。
バブルソートを使って、10万行の配列を昇順にソートできました。
結果
10万個のデータを、昇順にするのにかかる時間は、こちらとなりました。
「1415.4 秒」です。
やはり大量のデータを扱うには、バブルソートではちょっと遅いですね。
クイックソートで配列のソート
クイックソートという方法で、配列をソートする方法について説明します。
クイックソートとは
クイックソートは、プログラム自体は難しいんですけど、かなり速いです。
理論上では、一番高速らしいです。
配列の中のソートする範囲を分割して、入れ替えの手順を格段に減らすことで、高速しています。
クイックソートは、簡単に説明するとこんな手順になります。
クイックソートの手順
①基準の値を決める
②左側と右側から基準以上と以下の値を探して入れ替える
③左側ループと右側ループが交差したら探索範囲を分割する
④分割した範囲で①~③を繰り返す
⑤分割する範囲がなくなったら昇順完了
①基準の値を決める
基準は配列の中央の値を採用します。
②左側と右側から基準以上と以下の値を探して入れ替える
左側は基準以上の値を探します。右側は基準以下の値を探します。
これを入れ替えます。
『9』と『1』を入れ替えています。
これを繰り返していきます。
『5』と『3』を入れ替えています。
『8』と『4』を入れ替えています。
③左側ループと右側ループが交差したら探索範囲を分割する
左側のループと右側のループを繰り返していくと探索範囲が交差します。
交差したら左側と右側の探索範囲を分けます。ここが重要です。
探索範囲を分けていくことで入れ替える回数を減らすことができますのでその結果速度が速くなります。
④分割した範囲で①~③を繰り返す
左側と右側の範囲で①~③を繰り返していきます。
左側の範囲で①~③を繰り返していきます。
右側の範囲でも同じように①~③を繰り返していきます。
⑤分割する範囲がなくなったら昇順完了
範囲の分割を繰り替えしていくと最終的には分割する範囲がなくなっていきます。
分割する範囲がなくなると終了で配列のソートが完了します。
Excel VBAコード
クイックソートで配列をソートするExcel VBAはこちらになります。
Sub Test2()
t = Timer
Dim A
'データを取得
A = Range("A2:A100001")
'クイックソートを実行
Call SortAscending(A, LBound(A), UBound(A))
'データを貼り付け
Range("C2").Resize(UBound(A, 1)) = A
Debug.Print Timer - t & " 秒"
End Sub
Sub SortAscending(A, iLeft, iRight)
'中央値を取得
Dim iMid '中央値
iMid = A(Int((iLeft + iRight) / 2), 1)
i = iLeft '左側の探索用変数
j = iRight '右側の探索用変数
Dim B
'中央値から左側と右側の値を入れ替えていく
Do
'中央値から左側のループ
Do While A(i, 1) < iMid
'中央値以上の値まで右側に探索していく
i = i + 1
Loop
'中央値から右側のループ
Do While iMid < A(j, 1)
'中央値以下の値まで左側に探索していく
j = j - 1
Loop
'左側探索と右側探索の位置が交差したら終了
If i >= j Then Exit Do
'まだ交差していない場合、左側と右側の値を入れ替える
B = A(i, 1)
A(i, 1) = A(j, 1)
A(j, 1) = B
'左側は1つ右からスタート
i = i + 1
'右側は1つ左からスタート
j = j - 1
Loop
'中央値から左側を入れ替えていく(再帰)
If iLeft < i - 1 Then
Call SortAscending(A, iLeft, i - 1)
End If
'中央値から右側を入れ替えていく(再帰)
If j + 1 < iRight Then
Call SortAscending(A, j + 1, iRight)
End If
End Sub
Sub Test3()
t = Timer
Dim A
'配列を作成
A = Range("A2:A100001")
'別シートにデータを一時的に貼付け
Range("C2").Resize(UBound(A, 1)) = A
'Sort関数で昇順に並べ替え
Range("C2").CurrentRegion.Sort Key1:=Range("C2"), Order1:=xlAscending, Header:=xlNo
'昇順にしたデータを取得
A = Range("C2").CurrentRegion
'仮のデータを削除
Range("C2").CurrentRegion.Clear
Debug.Print Timer - t & " 秒"
End Sub