【VBA】挿入ソートの仕組みを徹底解説!途中経過のログ出力付きでアルゴリズムを可視化する
VBAには配列を直接並び替える専用の標準関数がないため、自分でソートアルゴリズムを実装する必要があります。今回は、未整列な要素を整列済みの適切な位置に挿入していくことで並び替える代表的なアルゴリズム「挿入ソート(Insertion Sort)」の解説と、途中経過のログ出力付きのVBA実装コードをご紹介します。
1. 挿入ソートとは?(仕組みと特徴)
挿入ソートは、左側のすでに整列済みの範囲に対し、右側の未整列な要素を1つずつ適切な位置に「挿入」していくアルゴリズムです。手札を順番に並べ替えるときのような動作をします。
- メリット:小規模なデータや、すでに「ほぼ整列されている」データに対して非常に高速に動作します。
- デメリット:データ数が多くなると処理速度が急激に落ちる(計算量 $O(n^2)$)。数万件以上の大量データには不向きです。
- 向いている場面:数十件〜数百件程度の小規模な配列の並び替え、またはほぼ整列済みのデータの最終整理。
- データ型の注意点:大小比較(
>演算子)を行うため、今回は「整数あるいは数値」のみが格納された配列を対象としています。(文字列や型が混在していると、エラーや意図しない順序になる原因となるため注意が必要です)
2. VBAコードの実装
【標準モジュールへの記述】
数値の配列を昇順(小さい順)に並び替えるプロシージャと、途中経過を表示する動作確認用のテストコードです。
Option Explicit
' 動作確認用テストコード(途中経過表示付き)
Public Sub TestInsertionSortWithLog()
Dim arr As Variant
' テスト用の配列を用意(バラバラの数値)
arr = Array(42, 15, 8, 99, 23, 4)
Debug.Print "=== ソート前 ==="
PrintArray arr
Debug.Print "-----------------------------"
' 挿入ソートの実行(途中経過を出力)
Call InsertionSortAscendingWithLog(arr)
Debug.Print "-----------------------------"
Debug.Print "=== ソート完了(最終結果) ==="
PrintArray arr
End Sub
' ======================================================================
' ■ 挿入ソート(昇順)の本体関数(途中経過ログ出力付き)
' 【前提条件】
' - 引数 targetArr は Variant型の1次元配列(ByRefによる参照渡し)
' - 配列の要素は「整数あるいは数値」のみを想定しています。
' ======================================================================
Public Sub InsertionSortAscendingWithLog(ByRef targetArr As Variant)
Dim i As Long, j As Long
Dim targetVal As Variant
Dim lBoundVal As Long, uBoundVal As Long
Dim stepCount As Long
On Error GoTo ErrorHandler
lBoundVal = LBound(targetArr)
uBoundVal = UBound(targetArr)
stepCount = 0
' 2番目の要素から最後まで順に処理を行う
For i = lBoundVal + 1 To uBoundVal
targetVal = targetArr(i)
j = i - 1
' 左側の要素と比較し、大きければ右へシフトしていく
Do While j >= lBoundVal
If targetArr(j) > targetVal Then
targetArr(j + 1) = targetArr(j)
j = j - 1
Else
Exit Do
End If
Loop
' 適切な位置に値を挿入する
targetArr(j + 1) = targetVal
' --- 途中経過の出力 ---
stepCount = stepCount + 1
Debug.Print "パス " & stepCount & " (値 " & targetVal & " を挿入後):"
PrintArray targetArr
Next i
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
' 配列の中身を安全に出力する補助プロシージャ
Private Sub PrintArray(ByRef targetArr As Variant)
Dim i As Long
Dim buf As String
For i = LBound(targetArr) To UBound(targetArr)
buf = buf & targetArr(i) & ", "
Next i
If Len(buf) > 0 Then buf = Left(buf, Len(buf) - 2)
Debug.Print " [" & buf & "]'
End Sub
' 動作確認用テストコード(途中経過表示付き)
Public Sub TestInsertionSortWithLog()
Dim arr As Variant
' テスト用の配列を用意(バラバラの数値)
arr = Array(42, 15, 8, 99, 23, 4)
Debug.Print "=== ソート前 ==="
PrintArray arr
Debug.Print "-----------------------------"
' 挿入ソートの実行(途中経過を出力)
Call InsertionSortAscendingWithLog(arr)
Debug.Print "-----------------------------"
Debug.Print "=== ソート完了(最終結果) ==="
PrintArray arr
End Sub
' ======================================================================
' ■ 挿入ソート(昇順)の本体関数(途中経過ログ出力付き)
' 【前提条件】
' - 引数 targetArr は Variant型の1次元配列(ByRefによる参照渡し)
' - 配列の要素は「整数あるいは数値」のみを想定しています。
' ======================================================================
Public Sub InsertionSortAscendingWithLog(ByRef targetArr As Variant)
Dim i As Long, j As Long
Dim targetVal As Variant
Dim lBoundVal As Long, uBoundVal As Long
Dim stepCount As Long
On Error GoTo ErrorHandler
lBoundVal = LBound(targetArr)
uBoundVal = UBound(targetArr)
stepCount = 0
' 2番目の要素から最後まで順に処理を行う
For i = lBoundVal + 1 To uBoundVal
targetVal = targetArr(i)
j = i - 1
' 左側の要素と比較し、大きければ右へシフトしていく
Do While j >= lBoundVal
If targetArr(j) > targetVal Then
targetArr(j + 1) = targetArr(j)
j = j - 1
Else
Exit Do
End If
Loop
' 適切な位置に値を挿入する
targetArr(j + 1) = targetVal
' --- 途中経過の出力 ---
stepCount = stepCount + 1
Debug.Print "パス " & stepCount & " (値 " & targetVal & " を挿入後):"
PrintArray targetArr
Next i
Exit Sub
ErrorHandler:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
' 配列の中身を安全に出力する補助プロシージャ
Private Sub PrintArray(ByRef targetArr As Variant)
Dim i As Long
Dim buf As String
For i = LBound(targetArr) To UBound(targetArr)
buf = buf & targetArr(i) & ", "
Next i
If Len(buf) > 0 Then buf = Left(buf, Len(buf) - 2)
Debug.Print " [" & buf & "]'
End Sub
3. 実行結果(イミディエイトウィンドウの出力)
実際に上記のコードをイミディエイトウィンドウで確認したところ、各ステップで要素が順番に正しい位置へ挿入されていく様子が確認できました。
=== ソート前 ===
[42, 15, 8, 99, 23, 4]
-----------------------------
パス 1 (値 15 を挿入後):
[15, 42, 8, 99, 23, 4]
パス 2 (値 8 を挿入後):
[8, 15, 42, 99, 23, 4]
パス 3 (値 99 を挿入後):
[8, 15, 42, 99, 23, 4]
パス 4 (値 23 を挿入後):
[8, 15, 23, 42, 99, 4]
パス 5 (値 4 を挿入後):
[4, 8, 15, 23, 42, 99]
-----------------------------
=== ソート完了(最終結果) ===
[4, 8, 15, 23, 42, 99]
[42, 15, 8, 99, 23, 4]
-----------------------------
パス 1 (値 15 を挿入後):
[15, 42, 8, 99, 23, 4]
パス 2 (値 8 を挿入後):
[8, 15, 42, 99, 23, 4]
パス 3 (値 99 を挿入後):
[8, 15, 42, 99, 23, 4]
パス 4 (値 23 を挿入後):
[8, 15, 23, 42, 99, 4]
パス 5 (値 4 を挿入後):
[4, 8, 15, 23, 42, 99]
-----------------------------
=== ソート完了(最終結果) ===
[4, 8, 15, 23, 42, 99]
4. まとめ
挿入ソートは、データの並び替え過程がログとして視覚的に分かりやすいアルゴリズムです。VBAでの配列操作や条件分岐の仕組みをステップアップして学びたいときは、ぜひこのコードを試してみてください。
PR