第11講 プロシージャの再帰的使用によって順列を生成する
第4話 普遍的な順列生成プログラム解説その2

入門
コード再掲
Dim x(15) As Byte, cn As Long, n As Byte
Private Sub CommandButton1_Click()
  n = Cells(3, 11)
  cn = 0
  f (
0)
End Sub
Sub f(g As Byte)
  Dim h As Byte, i As Byte, j As Byte, a As Byte, s As Long
  a = cn Mod 10
  s = Int(cn / 10)
  For
i = 1 To n
    x(g) = i
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If x(j) = x(g) 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 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
    End If
  Next
End Sub


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


   

で表すことにします。



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


 0

が生成します。
というのは、プロシージャは呼び出されたときのみ、
コンピュータのメモリ上に生じるからです。
  For i = 1 To n
    x(g) = i
最初にiに1が入ります。


 0
1

  For i = 1 To n
    x(g) = i
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If x(j) = x(g) 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 * s, 2 + (n + 1) * a + j) = x(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番目の世界(セル番号
の世界)


 0
1

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


 0
1 1

となります。g = 1ですから、
  For i = 1 To n
    x(g) = i
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If x(j) = x(g) Then
          h = 0
          Exit For
        End If
      Next
    End If
のIf文が実施され、j = 0のとき、
x(
g) = x(j) は x(1) = x(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 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
    End If
は遂行されません。したがって、Nextによりi=2となり、


 0
1 2

今度はj=0のとき、x(1)≠x(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 * s, 2 + (n + 1) * a + j) = x(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)を呼び出し、


 0
1 2

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


 0
1 2 1

となります。
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If x(j) = x(g) Then
          h = 0
          Exit For
        End If
      Next
    End If
は1回目のループすなわちj = 0のとき、
x(
g) = x(j) は x(2) = x(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 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
    End If
は遂行されず、Nextによりi=2となり、


 0
1 2 2

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

 0
1 2 3

となります。x(2)≠x(0)、x(2)≠x(1)なので、はじめて
    h = 1
    If g > 0 Then
      For j = 0 To g - 1
        If x(g) = x(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 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
    End If
が実行されるわけですが、g = 2 ですから
g + 1 < n は 2 + 1 < 3で成り立ちませんので、
Elseの部分が実行され
f (2)ははじめて自分だけに与えられている核ボタンを押す権限
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
を遂行して、


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

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




第3話へ 第5話へ



トップ

初心者のためのc++ vc++ c言語 入門 基礎から応用までへ
初心者のための excel 2007 2010 2013 vba マクロ 入門 基礎から応用まで
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
vb講義トップへ
VB講義基礎へ
専門用語なしのC++入門へ
専門用語なしのJava入門へ
専門用語なしのVBA入門

数独のページ
魔方陣のページ
数学研究室に戻る
本サイトトップへ