第9講 サブプロシージャの再帰的使用

第4話 スタック領域が足りないという謎の正体
  cn = cn + 1
  If cn = 11 Then Exit Sub
の2行を取り除いて
実行ボタンを押すと、
q
となってエラーしてしまいます。
終了ボタンを押して、
エクセルに戻ってみると、
w
1行だけ表示されていたり、
場合によっては、何千行も「今日は天気がよい」
が表示されてたりしています。
実は、
Dim cn As Integer
Private Sub CommandButton1_Click()

  CommandButton2_Click
  cn = 0
  
f 'CommandButton1_Clickがサブプロシージャfに仕事を依頼
End Sub
Sub f()

  Cells(4 + cn, 1) = "今日は天気がよい"
  
f 'fがfに仕事を依頼
  
End Sub
だと、無限ループの状態に陥っています。
fがfを呼び出すということが無限に続いてしまうのです。
本当は、エクセルシート上に無限に
「今日は天気がよい」
が表示されるはずなのですが、
スタック領域が足りなくなってエラーしてしまったので、
1行しか表示されないこともあるのです。
スタック領域が足りなくなるとは、
fの同じ姿をした人が、次々に舞台に上がり続けて、
舞台がfの分身によって、埋め尽くされてしまっている状態です。
もう舞台には隙間がなくなっているのに、
無理矢理fの分身が舞台に上がろうとして不具合を起こしたのです。
比喩でいったことを正確に言い直すと、
異なる番地のメモリ上にfがどんどん展開されてしまって、
メモリが足りなくなっている状態が、
スタック領域が足りない状態です。
プログラムは、注意していないとすぐに無限ループを引き起こします。
無限ループは、プログラムの宿痾です。
プログラマーは、常に無限ループに陥っていないかに、
気を配っていなければなりません。

  cn = cn + 1
  If cn = 11 Then Exit Sub
の意味は、fがfを呼び出すのを10回にとどめているということを意味します。
人形が自分の内側に人形を発生させるのを10回目までにしているということです。
プロシージャの再帰的呼び出しを使うときには、
必ず再帰的呼び出しをやめるタイミングをしてしてやらなければなりません。
今回は、カウンタcnで回数を数えさせ11回目のときにやめさせています。

さて、2つの謎が解けたところで、
サブプロシージャの再帰的呼び出しを使って、
第8講第4話以降で苦労して作ったn次順列を、
作成することにしましょう。
nはエクセルシートから、
取得する汎用的にして普遍的なプログラムを組んでみることにしましょう。
理論的には、nは1万でもOKですが、
現実には15以下が限界です。
理由は、15次でもすべて作成するとなると、
驚異的な計算能力を持つパソコンでも、
軽く1時間はかかるからです。
理由は、15次順列の場合の数は、
15×14×13×・・・×2×1=1307674368000
≒1京3兆個もあるからです。

では、
参考ダウンロード添付ファイル開いてAlt+F11をして、
VBAの画面にして下さい。すると、コードは
Dim a(20) As Integer, n As Integer, cn As Long
Private Sub CommandButton1_Click()

  CommandButton2_Click
  cn = 0
  n = Cells(4, 2)
  Call f(0) '9順列作成プロシージャ
End Sub

Sub f(g As Integer)


End Sub

Sub h()

  Dim i As Integer
  
  For i = 0 To n - 1
    Cells(5 + Int(cn / 5), 2 + i + (n + 1) * (cn Mod 5)) = a(i)
  Next
  cn = cn + 1
  
End Sub

Private Sub CommandButton2_Click()
  
  Rows("5:20000").Select
  Selection.ClearContents
  Cells(1, 1).Select
  
End Sub
となっています。

本来は、順列を収納する配列はローカル配列、
nとカウンタcnはローカル変数を用意すべきですが、
サブプロシージャの再帰的使用の構造がよく見えるように、
はじめはグローバル配列とグローバル変数
Dim a(20) As Integer, n As Integer, cn As Long
で宣言してあります。
もちろん、構造が見えた段階でこれらはローカル配列とローカル変数に宣言し直します。
皆さんに、空白となっている
Sub f(g As Integer)


End Sub
にコードを入れて頂いて、B4に数字を入れて実行ボタンをクリックすると、
e
r
等が実現できるようにして頂きたいのです。

Sub f(g As Integer)のgは、
第8講第4話以降のa(2)等の()の中の数字に対応します。
すべての場合を実現しなければなりませんので、
fの中身は、For文となります。
a(0)に中身が入った後は、
fがfを呼び出すことによって、fが自分の分身を作り、
a(1)の入力を担当させます。
さらに、a(1)がはいった後は、
fの分身が、再びfの分身の分身を作り出し、
fの分身の分身は、a(2)の入力を担当します。
図にしますと、
f                  ・・・a(0)
fの分身              ・・・a(1)
fの分身の分身         ・・・a(2)
fの分身の分身の分身    ・・・a(3)
         *
         *
         *
ということになります。




第3話へ 第5話へ
004

eclipse c++ 入門
魔方陣 数独で学ぶ VBA 入門
数独のシンプルな解き方・簡単な解法の研究
vc++講義へ
excel 2013 2010 2007 vba入門へ
VB講義基礎へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座へ
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座へ
専門用語なしの C言語 C++ 入門(Visual C++ 2010で学ぶ C言語 C++ 入門)
専門用語なしの excel vba マクロ 入門 2013 2010 2007 対応講義 第1部
eclipse java 入門へ
excel 2016 vba 入門へ第2部へ
小学生からエンジニアまでのRuby入門へ
本サイトトップへ