VBAサンプル集
1次元配列の並べ替え(バブルソート,挿入ソート,クイックソート)

ExcelマクロVBAの実用サンプル、エクセルVBA集と解説
最終更新日:2019-10-29

1次元配列の並べ替え(バブルソート,挿入ソート,クイックソート)


配列(1次元)の並べ替え方法について、バブルソート、挿入ソート、クイックソートのサンプルになります。
元来エクセルには、ワークシートの並べ替え機能があります。
ワークシートにデータを書き出して、ワークシートの並べ替え機能を使えるのですが、
どうしても、配列をワークシートに途中で書き出すと言うのは面倒なものです。
そこで、配列を並べ替える必要が出てきます。


アルゴリズムの解説ではなく、あくまでVBAでの実装サンプルになります。
ソートアルゴリズムについては、詳細に解説しているサイトをご覧ください。

検証方法

Sheet1A1~A10000にランダムなデータを入れました。
これを(昇順に)並べ替えて、Sheet2 に出力しています。

Sub ソート検証()
  Dim ws1 As Worksheet
  Dim ws2 As Worksheet
  Dim myAry1()
  Dim myAry2()
  Dim i As Long
  Set ws1 = Worksheets("Sheet1")
  Set ws2 = Worksheets("Sheet2")
  myAry1 = ws1.Range("A1:A10000").Value
  
  'myAry1は2次元配列なのでmyAry2で1次元配列に変更
  ReDim myAry2(LBound(myAry1) To UBound(myAry1))
  For i = LBound(myAry1) To UBound(myAry1)
    myAry2(i) = myAry1(i, 1)
  Next
  
  '1次元配列ソート
  Dim start As Double: start = Timer
  'Call バブルソート(myAry2)
  'Call 挿入ソート(myAry2)
  'Call クイックソート(myAry2, LBound(myAry2), UBound(myAry2))
  Debug.Print Timer - start
  
  'myAry2は1次元配列なのでmyAry1で2次元配列に変更
  For i = LBound(myAry2) To UBound(myAry2)
    myAry1(i, 1) = myAry2(i)
  Next
  ws2.Cells.Clear
  ws2.Range("A1:A10000").Value = myAry1
End Sub

ソートごとに、
Call バブルソート(myAry2)
Call 挿入ソート(myAry2)

Call クイックソート(myAry2, LBound(myAry2), UBound(myAry2))
この3行のいずれか1つだけにして実行しています。
複数回実行し、所要時間の平均時間の概数を記載しています。
時間はデータとPC環境にかなり依存しますので、あくまで目安になります。

バブルソート

ソートのアルゴリズムの中で、簡単で理解しやすいのは、バブルソートでしょう 。
バブルは「泡」のことで、並べ替えの過程でデータが下から上(上から下)へ移動する感じが、泡が浮かんでいく様に見えることからこの名前が付いているそうです。

Sub バブルソート(ByRef argAry() As Variant)
  Dim vSwap As Variant
  Dim i As Integer
  Dim j As Integer
  For i = UBound(argAry) To LBound(argAry) Step -1
    For j = LBound(argAry) To i - 1
      If argAry(j) > argAry(j + 1) Then
        vSwap = argAry(j)
        argAry(j) = argAry(j + 1)
        argAry(j + 1) = vSwap
      End If
    Next j
  Next i
End Sub

外側のFor~Nextの1回目が終わった時点で、配列の最後尾に最大値が来ます。
以下、2回目のループで配列の最後から2番目に2番目に大きいデータが来ます。
これの繰り返しになっています。

If argAry(j) > argAry(j + 1) Then
これを
If argAry(j) < argAry(j + 1) Then
とすれば、降順の並べ替えになります。

非常に単純ですが、処理時間がかかる事が難点です。
データ件数が、少なければ単純で良いでしょう。
では、その処理時間を見てみます。

1万件で2.7秒です。
1万件で2.7秒なら、遅いけど待てない時間ではないでしょうか、それでも件数的には限界でしょうね。
件数を増やすと、
2万件で約13秒かかってしまいます。
これはかかりすぎですね、実際に使用するとなると数千件以内に限定されそうです。

挿入ソート

挿入ソート(インサーションソート)は、
整列してある配列に追加要素を適切な場所に挿入することで並べ替えを行っています。
アルゴリズムは非常に単純でVBAも簡単です。

Sub 挿入ソート(ByRef argAry() As Variant)
  Dim Low As Long
  Dim Upp As Long
  Low = LBound(argAry)
  Upp = UBound(argAry)
  Dim i As Long, j As Long
  Dim vSwap As Variant
  For i = Low + 1 To Upp
    vSwap = argAry(i)
    For j = i - 1 To Low Step -1
      If argAry(j) > vSwap Then
        argAry(j + 1) = argAry(j)
      Else
        Exit For
      End If
    Next
    argAry(j + 1) = vSwap
  Next
End Sub

基準位置(i)を、それより前の配列の適切な位置に挿入していくことで並べ替えています。
元の並び順がある程度そろっているときは速いのですが、逆順に並んでいると遅くなります。
では、その処理時間を見てみます。

1万件で約0.81秒
2万件で約3.22秒
ただし、
バブルソートよりは速そうですが、もし、全く逆順になっているデータの場合、
1万件で約1.78秒
2万件で約7.18秒
このように、かなり時間が違ってきます。
データ順がはっきりしていない場合には、やはり1万件程度までが実質的な使用範囲でしょうか。

クイックソート

さらに、高速なソートアルゴリズムはないのか・・・
いろいろ沢山あるようですが、その一つとしてクイックソートがあります。
クイックソートは一般的にかなり高速だといわれてはいますが、
アルゴリズムとしてはいろいろな亜種があるらしいです。
ここでは、ごく一般的な方法を採用しています。
アルゴリズムの詳細は説明が長くなってしまいますので、専門に解説しているページを参照して下さい。

Sub クイックソート(ByRef argAry() As Variant, _
          ByVal lngMin As Long, _
          ByVal lngMax As Long)
  Dim i As Long
  Dim j As Long
  Dim vBase As Variant
  Dim vSwap As Variant
  vBase = argAry(Int((lngMin + lngMax) / 2))
  i = lngMin
  j = lngMax
  Do
    Do While argAry(i) < vBase
      i = i + 1
    Loop
    Do While argAry(j) > vBase
      j = j - 1
    Loop
    If i >= j Then Exit Do
    vSwap = argAry(i)
    argAry(i) = argAry(j)
    argAry(j) = vSwap
    i = i + 1
    j = j - 1
  Loop
  If (lngMin < i - 1) Then
    Call クイックソート(argAry, lngMin, i - 1)
  End If
  If (lngMax > j + 1) Then
    Call クイックソート(argAry, j + 1, lngMax)
  End If
End Sub

このアルゴリズムをすっきり理解するのは大変ですね。
基準値を決め、大きい値のグループと小さい値のグループに分けることを繰り返します。
これを再帰プロージャーで、範囲を狭めながら繰り返しています。
これにより並べ替えを実現しています。
では、その処理時間を見てみます。

1万件で約0.011秒
2万件で約0.022秒
10万件で約0.091秒
100万件で約1.46秒
やはり断然はやいですね。
件数が増えても、実用として問題ない数値だと思います。

最後に

数百件程度の配列なら、バブルソートでもよいですが、
それ以上になるなら、やはりクイックソートが好ましいでしょう。

今回の実行例でもそうですが、
やはり、配列は2次元になる場合が多いです。
そこで、次回は、
2次元配列の並べ替え
・検証方法 ・バブルソート ・クイックソート ・複数キーでの並べ替えについて ・ワークシートを使って並べ替え・・・番外編



同じテーマ「マクロVBAサンプル集」の記事

1次元配列の並べ替え(バブルソート,挿入ソート,クイックソート)
2次元配列の並べ替え(バブルソート,クイックソート)
Dir関数で全サブフォルダの全ファイルを取得
順列の全組み合わせ作成と応用方法
スピルに対応したXSPLITユーザー定義関数(文字区切り)


新着記事NEW ・・・新着記事一覧を見る

数字(1~50)を丸付き数字に変換するVBA|VBA技術解説(2022-11-15)
TEXTAFTER関数(テキストの指定文字列より後ろの部分を返す)|エクセル入門(2022-11-14)
TEXTBEFORE関数(テキストの指定文字列より前の部分を返す)|エクセル入門(2022-11-14)
TEXTSPLIT関数(列と行の区切り記号で文字列を分割)|エクセル入門(2022-11-12)
LAMBDA以降の新関数はVBAで使えるか|VBA技術解説(2022-11-11)
WRAPCOLS関数(1次元配列を指定数の列で折り返す)|エクセル入門(2022-11-08)
WRAPROWS関数(1次元配列を指定数の行で折り返す)|エクセル入門(2022-11-08)
EXPAND関数(配列を指定された行と列に拡張する)|エクセル入門(2022-11-07)
TAKE関数(配列の先頭/末尾から指定行/列数を取得)|エクセル入門(2022-11-06)
DROP関数(配列の先頭/末尾から指定行/列数を除外)|エクセル入門(2022-11-06)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.RangeとCellsの使い方|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.繰り返し処理(For Next)|VBA入門
5.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
6.Excelショートカットキー一覧|Excelリファレンス
7.並べ替え(Sort)|VBA入門
8.エクセルVBAでのシート指定方法|VBA技術解説
9.マクロって何?VBAって何?|VBA入門
10.ExcelマクロVBAの基礎を学習する方法|エクセルの神髄




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、
間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。
掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ