« 「より高速な VBA マクロ」について | トップページ | 友愛数 »

2011年1月 1日 (土)

配列をソートする

参照URL:
How to Use a Visual Basic Macro to Sort Arrays in Excel

上記ページによると
VBAで配列を直接ソートする方法はないようです。
代わりに2つの方法

Selection Sort
Bubble Sort

が例示されています。

訳して簡単に説明します。

Selection Sort

プログラムするのが簡単だが、
大きい配列ではthe Bubble Sortより遅い。

要素が1からnまでの配列でSelection Sortをする。

この配列の1からnまでの中で一番大きい要素を見つける。
これがn番目の要素でない(Indexがnより小さい)なら、
これをn番目と入れ替える。

それから、
1からn-1までの中で一番大きい要素を見つける。
これがn-1番目の要素でないなら、
これをn-1番目と入れ替える。

1から2までの中で一番大きい要素を見つける。
これが2番目の要素でないなら、
これを2番目と入れ替える。

Bubble Sort

Selection Sortよりプログラムするのが難しいが、
大きい配列をソートする場合はより速く効果的の傾向。

1からn-1までの要素をそれぞれ次の要素と比較し
次の要素のほうが小さいなら入れ替える。
これを入れ替えがなくなるまで繰り返す。

以上で訳終了。

Function SelectionSort、
Function BubbleSortNoteは共に昇順で並び替える方法で、
最後のほうのNoteで降順にする方法が書かれています。

昇順(ascending order)
降順(descending order)

この2つ
いつもどっちが大きいほうからで
どっちが小さいほうからか考えてしまします。

昇順が列の上から下の方向へ大きくなっていく、
降順が列の上から下の方向へ小さくなっていく。

言い換えると、
昇順が列の一番上に小さいものが来て、
降順が列の一番上に大きいものが来る。

列の”下へ向って昇っていく”というところが
感覚と合わないところですね。

さて
Function SelectionSort、Function BubbleSortNoteを改造して
昇順、降順を1つのプロシージャでできるようにします。

それには、引数Orderを1つ増やして
昇順、降順を指定します。

Order = 0 を昇順、
Order = 1を降順にします。

これをIf文で分岐するだけのことです。

コードはこちら

Selection Sortするコード:

Function SelectionSort2(TempArray As Variant, Order As Integer)
'Option Base 1で実行
'Order = 0 昇順
'Order = 1 降順

    Dim MaxVal As Variant '最大値/最小値
    Dim MaxIndex As Integer
    Dim i, j As Integer
   
    If Order <> 0 And Order <> 1 Then
        MsgBox "Orderは0か1を指定してください。"
        Exit Function
    End If
    ' 配列の後ろから前へ
    For i = UBound(TempArray) To 1 Step -1

        '配列の最大要素の値とインデックス
        MaxVal = TempArray(i)
        MaxIndex = i

        ' 残りの要素とMaxValを比較しMaxValより大きいなら
        'その要素をMaxValにする
        For j = 1 To i
            If Order = 0 Then
                '昇順
                If TempArray(j) > MaxVal Then
                    MaxVal = TempArray(j)
                    MaxIndex = j
                End If
            ElseIf Order = 1 Then
                '降順
                If TempArray(j) < MaxVal Then
                    MaxVal = TempArray(j)
                    MaxIndex = j
                End If
            End If
        Next j

        ' 残りの要素の最大要素のインデックスがiでないなら
        'その要素とiを入れ替える
        If MaxIndex < i Then
            TempArray(MaxIndex) = TempArray(i)
            TempArray(i) = MaxVal
        End If
    Next i

End Function

Sub macro110101b()
'SelectionSort2使用例

    Sheets.Add
   
    Dim TheArray As Variant
    Dim i As Integer
   
    ' ソートする配列
    TheArray = Array(15, 8, 11, 7, 33, 4, 46, 19, 20, 27)
    Range("A1") = "SelectionSort元"
    For i = 1 To 10
        Cells(i + 1, 1) = TheArray(i)
    Next i

    ' ソート(昇順)
    Call SelectionSort2(TheArray, 0)
    Range("B1") = "昇順"
    For i = 1 To 10
        Cells(i + 1, 2) = TheArray(i)
    Next i
   
    ' ソート(降順)
    Call SelectionSort2(TheArray, 1)
    Range("C1") = "降順"
    For i = 1 To 10
        Cells(i + 1, 3) = TheArray(i)
    Next i
   
End Sub

Bubble Sortするコード:

Function BubbleSort2(TempArray As Variant, Order As Integer)
'Option Base 1で実行
'Order = 0 昇順
'Order = 1 降順

    Dim Temp As Variant
    Dim i As Integer
    Dim NoExchanges As Integer

    ' ループの終わりでNoExchanges = Trueで終了
    Do
        NoExchanges = True

        For i = 1 To UBound(TempArray) - 1
            If Order = 0 Then
                '昇順
                If TempArray(i) > TempArray(i + 1) Then
                    NoExchanges = False
                    Temp = TempArray(i)
                    TempArray(i) = TempArray(i + 1)
                    TempArray(i + 1) = Temp
                End If
            ElseIf Order = 1 Then
                '降順
                If TempArray(i) < TempArray(i + 1) Then
                    NoExchanges = False
                    Temp = TempArray(i)
                    TempArray(i) = TempArray(i + 1)
                    TempArray(i + 1) = Temp
                End If
            End If
        Next i
    Loop While Not (NoExchanges)

End Function

Sub macro110101a()
'BubbleSort2使用例

    Sheets.Add
   
    Dim TheArray As Variant
    Dim i As Integer
   
    ' ソートする配列
    TheArray = Array(15, 8, 11, 7, 33, 4, 46, 19, 20, 27)
    Range("A1") = "BubbleSort元"
    For i = 1 To 10
        Cells(i + 1, 1) = TheArray(i)
    Next i

    ' ソート(昇順)
    Call BubbleSort2(TheArray, 0)
    Range("B1") = "昇順"
    For i = 1 To 10
        Cells(i + 1, 2) = TheArray(i)
    Next i
   
    ' ソート(降順)
    Call BubbleSort2(TheArray, 1)
    Range("C1") = "降順"
    For i = 1 To 10
        Cells(i + 1, 3) = TheArray(i)
    Next i
   
End Sub

macro110101a実行後のシート

Vba20110101a

上の2つの方法は1次元配列しかソートできないので
使いにくいです。

それにしてもBubble Sortってなんで
バブルという名前なんでしょうか?
たくさんクルクルするからなんでしょうかね~

|

« 「より高速な VBA マクロ」について | トップページ | 友愛数 »

コメント

Bubble Sortするコードなのですが、エラーになりました。

配列の範囲が0~9なのにソートのときに
For i = 1 To 10と指定していて
TheArray(10)が存在しないのでエラーになるようです。

上記を修正しても、類似内容の問題が別にありました。

For i = 1 To UBound(TempArray) - 1
以下の範囲のTempArray(i)も、
TempArrayは0~9なので描かれているものだと
配列の1~8で並べ返してしまい並べ替え範囲から
もれている配列があって綺麗にならびませんでした。


追記:管理人やむえむ
コメントありがとうございます。
現在、トラブルで別のコメントで返信できないので、
こちらのコメント内にて返信いたします。

上記コードは
「Option Base 1」で実行してください。
通常、配列の番号は0から始まります。
「Option Base 1」と指定することで、
配列の番号を1から始めることを指定できます。

「Option Base 1」で実行するには、
コードの一番上に「Option Base 1」と入力してください。

今後とも
当ブログをよろしくお願いします。

投稿: 通りすがり | 2012年12月14日 (金) 12時13分

バブルソートはターゲット値が水中の泡のように浮いていくからそう呼ばれてます。

投稿: | 2013年4月 2日 (火) 14時57分

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: 配列をソートする:

« 「より高速な VBA マクロ」について | トップページ | 友愛数 »