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

入門
コード再掲
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


解説

 0
2 1 3

これでf (2)の3回目の生は終わりを告げ、消滅しf (1)へと戻ります。


 0
2 1

そして、Nextにより


 0
2 2

となりますが、これは
    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により


 0
2 3

今回は
    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
命令が実施され、f (
2)の4回目の発生となります。


 0
2 3

  For i = 1 To n
    x(g) = i
によって

 0
2 3 1

3つともセルの内容が違いますので、
試験
    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
の否定側の
      Else
        For j = 0 To n - 1
          Cells(5 + 2 * s, 2 + (n + 1) * a + j) = x(j)
        Next
        cn = cn + 1
      End If
の命令が遂行され、4個目の順列
をシートにはき出します。
Nextにより、

 0
2 3 2

となりますが、これは1番目のセルと3番目のセルが同じなので、
検査
    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
に抵触して、


 0
2 3 3

となります。
今度は、2番目のセルと3番目のセルの内容が同じなので、やはり
    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
の試験をクリアできません。
これで、f (
2)の4回目の生が寿命を迎え、消滅します。


 0
2 3

そして、セル番号1の世界も天寿を全うし、
2度目の消滅を体験します。


 0
2

Nextにより


 0
3

となり、g=0なので試験
    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
の肯定側
      If g + 1 < n Then
        f (g + 1)
が実行されf (1)の3度目の誕生を迎えます。

 0
3

  For i = 1 To n
    x(g) = i
によって、


 0
3 1

これは、2つのセルに内容が違いますので、
    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
の肯定部分が遂行され、f (2)の5度目の生誕となります。

 0
3 1 i

For文によって


 0
3 1 1



 0
3 1 2

と変化していって、はじめて3つのセルの内容がすべて異なり、
      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
の否定部分の命令が遂行され5個目の順列
がシートに出力されます。
以下、


 0
3 1 3

セル番号の世界の5度目の消滅。


 0
3 1



 0
3 2



 0
3 2 1

と変化していき、6個目の順列
がシートに打ち出されます。

 0
3 2 2



 0
3 2 3

セル番号の世界の6度目の消滅。


 0
3 2



 0
3 3

セル番号の世界の3度目の消滅。


 0
3

セル番号0の世界のはじめての消滅を迎え、
プログラムはf (0)を呼び出してから
はじめてPrivate Sub CommandButton1_Clickに戻り、
自分の任務をすべて完遂し終焉を迎えます。
プログラムは、消滅しましたが、シートには結果

が燦然と輝いています。

最後の方、叙述を簡単にしましたが、
簡略にした部分を皆さんが補ってください。
詳しい記述を延々と繰り返したのでは、
逆に読む気力が失せると考え、簡単にしました。

n=3を選んだ理由はお分かりですね。
n=2ではトレースとして簡単すぎます。
しかし、n=4では、私も書く気になれませんし、
読む皆さんもウンザリですよね。

みなさん、n=4のトレースは大変ですが、
頭の中でやってみてください。
コンピュータの動きを追うことはとても大切なことです。

では、皆さんわかりやすさを優先して、
Dim x(15) As Byte, cn As Long, n As Byte
をグローバルとして
引数1つのプロシージャSub f(g As Integer)としましたが、
グローバル配列とグローバル変数をやめて、
プロシージャもSub f(g As Integer,cn As Long,n As Byte,x() As Byte)と
引数を4つにするプログラムを考えてください。
尚、x() As Byteのようにすれば配列も引数として引き渡すことが出来ます。
その場合fを呼び出すには Call f(0, cn, n, x()) のようにします。
Subプロシージャが2つ以上の引数を持つときは、
Callを省略することができません。
省略したいときは、f 0,cn,n,x() となります。
これは私の趣味には合いませんので、
私はCall f(0, cn, n, x())としています。
尚、C言語やC++などではf(0, cn, n, x())とすることは可能です。




第5話へ 第7話へ



トップ

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

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