第11講 Subプロシージャの再帰的使用の学習

第5話 Subプロシージャ版順列作成の解説その2

Dim a(15) As Byte
Dim cn As Long
Dim n As Byte
Private Sub CommandButton1_Click()
  n = Cells(2, 10)
  cn = 0
  f (0)
  Cells(3, 13) = cn
End Sub

Sub f(g As Integer)
  Dim i As Byte, j As Byte, h As Byte
  For i = 1 To n
    a(g) = i
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If a(g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
    If h = 1 Then
      If g + 1 < n Then
        f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
  Next

End Sub

解説
Dim a(15) As Byte
Dim cn As Long
Dim n As Byte
はグローバルにしないで、f g,cn,n,a() としてプロシージャを呼び出すことも出来ますが、
次元を決定づけているものはgであることを強調するために、
今回はa(15)とcn、nはグローバル配列とグローバル変数にしてあります。このためにf(g)というすっきした呼び出しになっています。
尚、f g,cn,n,a() の a() は配列を引数として引き渡しています。配列も引数として引き渡しが出来ます。
  n = Cells(2, 10)
  cn = 0
1行目で、J2から順列の次数を取得しています。
2行目で初期化しています。cnは、順列総数を数えるカウンタ(数えるものという意味です)変数です。
さて、トレースを今からしていきますが、現在どのセル番号の世界にいるのかを常に明確に意識しながら、以下をお読みください。
現在どのセルにいるのかをはっきり掴んでいないと、トレースが理解できなくなります。
現在いるセル(現在アクティブなセル)を

  

で表すことにします。



また、n=3の場合n=3でトレースしていることも念頭においてください。
  f (0)
ではじめて、世界

が生成します。
  For i = 1 To n
    a(g) = i
最初にiに1が入ります。

1

    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If a(g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
g=0ですから、If文は実行されず、h=1は書き換えられず、
    If h = 1 Then
      If
g + 1 < n Then
        
f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
実行されます。
g=0ですから、g + 1 < nは 0+ 1 < nすなわち1 < 3 で成り立ちますので、
        f (
g + 1)
の命令が遂行されます。
g=0ですから、f (g + 1)はf (1)です。したがって、f (0)がf (1)を呼び出しました。
その結果、2番目の世界(セル番号
の世界)

1

が発生します。
  For i = 1 To n
    a(g) = i
によって、

1 1

となります。g=1ですから、
    h = 1
    If
g > 0 Then
      For j = 0 To g - 1
        If a(g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
のIf文が実施され、j=0のとき、a(
g) = a(j) は a(1) = a(0) となりh=0となり(セル番号の世界にいるからですよ。)
    If h = 1 Then
      If
g + 1 < n Then
        
f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
は遂行されません。したがって、Nextによりi=2となり、

1 2

今度はj=0のとき、a(1)≠a(0)なので、h=1は書き換えられず、
    If h = 1 Then
      If
g + 1 < n Then
        
f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
が実行されます。
g=1ですから、g + 1 < nは 1 + 1 < 3で真ですから、
        f (
g + 1)すなわちf (2)
の命令が遂行されます。すなわち、f (
1)がf (2)を呼び出し、

1 2

3番目の世界(g=2の世界)が誕生します。
  For i = 1 To n
    a(g) = i
によって、i=1が入り、

1 2 1

となります。
    h = 1
    If
g > 0 Then
      For j = 0 To g - 1
        If a(
g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
は1回目のループすなわちj=0のとき、a(
g) = a(j) は a(2) = a(0)となり、h=0となり、
    If h = 1 Then
      If g + 1 < n Then
        f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
は遂行されず、Nextによりi=2となり、

1 2 2

となります。
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If a(g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
今回は、2回目のループすなわちj=1のとき、a(g) = a(j) は a(2) = a(1)となり、
    If h = 1 Then
      If g + 1 < n Then
        f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
は実施にいたらず、Nextにより

1 2 3

となります。a(2)≠a(0)、a(2)≠a(1)なので、はじめて
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If a(g) = a(j) Then
          h = 0
          Exit For
        End If
      Next
    End If
のチェックをクリアして、
    If h = 1 Then
      If g + 1 < n Then
        f (g + 1)
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
    End If
が実行されるわけですが、g=2ですからg + 1 < n は2 + 1 < 3で成り立ちません。
よって、f (2)ははじめて自分だけに与えられている核ボタンを押す権限
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * Int(cn / 10), 1 + (n + 1) * (cn Mod 10) + j) = a(j)
        Next
        cn = cn + 1
      End If
を遂行して、


シートに1個目の順列1個目の順列を表示させることに成功します。

本日のトレースはここまで。これ以降のトレースは次話で。

第4話へ 第6話へ

004
  


VBA講義第1部へ
vc++講義へ
vb講義へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ

数学研究室に戻る