午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

エクセルVBAでシェルソート

 
 
今回は挿入ソートの改良型のシェルソート
 
挿入ソートでは常に隣と比較していたのを離れたところと比較してから、だんだん近くのものと比較していって、最終的には隣と比較するところ
たったこれだけみたい
しかもこれはバブルソートをコムソートに改良した方法とそっくり
 
3,4,2,6,1,5,3を整列するとき
間隔が3だった場合は
イメージ 1
同じグループ同士で挿入ソートする
イメージ 2
0番、3番、6番が同じグループ
1番、4番
2番、6番
グループ同士で整列完了
イメージ 3
間隔を狭くして2だったら
イメージ 4
0,2,4,6番のグループ
1,3,5番のグループ
それぞれを挿入ソートで
イメージ 5
整列
イメージ 6
 
 
次は間隔1
イメージ 7
間隔1は隣同士だから
グループ分けなしの普通の挿入ソートで整列完了
 
重要なのは間隔(h)をいくつにするかみたいで、これの求め方はWikipediaを見ると...見てもよくわかんないだよなあ、数式が書いてあるんだけど見方がわからんwけど例が書いてあって1,4,13,40,121...(3^i-1)/2ってある
どうやら「i」ってのが順番みたいで(3^i-1)/2の「i」に1から順番に整数を入れてみると
イメージ 17
同じ数値がでてきた!
 
 
配列を渡すとシェルソートに使う間隔の配列を返すマクロ
Public Function GetH2(v As Variant) As Long()
    Dim l() As Long
    Dim vc As Long
    vc = UBound(v) - LBound(v) + 1 '要素数
    Dim i As Long: i = 1
    Do
        ReDim Preserve l(i - 1)
        l(i - 1) = ((3 ^ i) - 1) / 2
        i = i + 1
    Loop While ((3 ^ i) - 1) / 2 < vc
    GetH2 = l
End Function
これに例えば10万件の要素がある配列を渡すと
イメージ 8
必要な間隔の配列を返す
1,4,13,40,121,364,1093,3280,9841,29524,88573
こうしてみると10万件でも11回しか変更しないんだなあ
 
あとは挿入ソートにこの間隔を使うだけだから前回のtestInsertion2を書き直してできたのがtestShellSort1
Public Function testShellSort1(v As Variant) As Variant
    Dim i As Long, j As Long, k As Long
    Dim tmp As Variant
    Dim hs() As Long
    hs = GetH2(v) '間隔の配列取得
    Dim h As Long '間隔用
    For k = UBound(hs) To 0 Step -1 '大きい方から使うからStep -1
        h = hs(k) '間隔
        For i = LBound(v) + h To UBound(v)
            tmp = v(i)
            For j = i - h To LBound(v) Step -h
                If v(j) > tmp Then '比較
                    v(j + h) = v(j) '右へコピー
                Else
                    Exit For 'ループ抜けしてtmpを配列に戻す
                End If
            Next
            v(j + h) = tmp 'tmpを配列に戻す
        Next
    Next
    testShellSort1 = v
End Function
 9~19行目が挿入ソートなので前回とほとんど一緒、違うのは-1と+1だったのが-hと+hになっただけ
 
間隔の配列は小さい方から入っているけど使う順番は大きい方からだからFor~NextのStepを-1
 
 
ランダム数値1万件の並べ替えの処理時間計測
イメージ 9
3回計測
速い、コムソート並に速い!
 
0.0625秒はコムソートでも計測されていた
もしかしたら今の方法ではこれ以上小さい値は計測できないのかも?
ってことで100万件で計測、コムソートと比べてみる
イメージ 10
13秒前後なので9秒前後のコムソートよりは遅いねえ
でもかなり速い
 
時間計測するマクロ
Sub sortTestBubble2()
    Dim c As Long: c = 1000000
    Dim v() As Variant
    ReDim v(c - 1)
    Randomize
    For i = 0 To c - 1
        v(i) = CLng(c * Rnd)
    Next
    Dim st As Single
    st = Timer
'  v = testBubble1(v) '18.90234秒
'  v = testBubble2(v) '12.27734
   'v = testBubble3(v)  '10.16406
   'v = testShaker2(v) '10.63281
   'v = testShaker3(v) '7.078125
'  v = testComb2(v) '0.0625
    v = testShellSort1(v) '0.0625
    MsgBox Timer - st & "秒"
End Sub
 
 
 
 
 
いままでのまとめ
イメージ 11
異次元レベルだったコムソートに匹敵するシェルソート
 
 
 
 
シェルソートで重要な間隔hを決める方法は色々あるみたいで
シェルソートと間隔hの決め方【C++】 - Programming Magic
http://www.programming-magic.com/20100507074241/
なんかスゴイ、
hn = 4n+3*2n-1+1
(ただし、h0 = 1)
これで求めるとさっきの方法より速いみたい、でもやっぱり見方がわからん
 
Programming Place Plus アルゴリズムとデータ構造編【整列アルゴリズム】 第5章 シェルソート(挿入ソートの改良)
http://ppp-lab.sakura.ne.jp/ProgrammingPlacePlus/algorithm/sort/005.html
ここ見てたらWikipedia
イメージ 12
これでわかったわ、hi+1=3hi+1ってところ
iは配列で言う添字とかインデックスだわ
iがもし2の場合は2番めの間隔(h)ってことで
左辺はiに+1しているから3番目の間隔ってことで右辺はその3番目の値を求める式ってことだから
3hiは2番めの間隔の値*3ってことだわ
一番小さい間隔は1で決まっているからこれが最初で0番目
次の1番目は3*1+1=4
次の2番めは3*4+1=13
次の3番めは3*13+1=40
であってる
イメージ 16
下付き文字の「i」はインデックスだった
だからi+1は次の値って意味だったのかあ
なんか算数の授業で習った気もしてきた...30年くらい前
 
hn = 4n+3*2n-1+1
(ただし、h0 = 1)
でもこれの見方わかったので試してみる
 
Public Function GetH3(v As Variant) As Long()
    Dim l() As Long
    Dim vc As Long
    vc = UBound(v) - LBound(v) + 1 '要素数
    Dim i As Long: i = 1
    ReDim l(0)
    l(0) = 1
    Do
        ReDim Preserve l(i)
        l(i) = 4 ^ i + 3 * 2 ^ (i - 1) + 1
        i = i + 1
    Loop While 4 ^ i + 3 * 2 ^ (i - 1) + 1 < vc
    GetH3 = l
End Function
 
これに10万件の配列を渡すと
イメージ 13
1,8,23,77,281,1073,4193,16577,65921っていう配列が返ってきた、比べると
1,4,13,40,121,364,1093,3280,9841,29524,88573
 
 
イメージ 14
変化を少しなだらかにして大雑把にした感じかなあ
これを使って100万件ソートで比較
イメージ 15
testShellSort2がそれなんだけど、速い!
コムソートより速くなった!すっごーい!
 
 
前回
エクセルVBAで挿入ソート ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14799218.html
 
エクセルVBAバブルソート ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14787146.html
ソートアルゴリズムまとめ
エクセルVBAで、ソートアルゴリズムとデータの違いによるソート処理時間比較 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/14836198.html