マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第9章 関数の再帰的使用

第8話 部屋数3・生徒数3の場合におけるトレースその1

プログラムコード再掲

#include<iostream>//インクルードファイルiostreamの読み込み

#include<conio.h>//while(!_kbhit());を使うためのお呪い

#include<strins> //文字列変数を使えるようにするために組み込む

#include <iomanip> //setprecisionを使えるように組み込む

#include <cmath>//powなどを使うときに必要

#include <ctime>//time()(←現時刻発生する関数)を使うために必要

using namespace std;//coutを使うときに必要なお呪い

const int n = 5;//具体的な数字を使うのではなく、 n を使うと汎用性のあるプログラムになる!

void f(int s);//順列生成関数←引数名をgからsに変更(2026年3月19日)

int a[25]; //将来5次魔方陣まで生成できるように25に変更

int cn = 0; //anに変更 変更理由はnuberの頭文字nは整数を表す場合が多いからです

int main() {

              f(0);

              cout << endl << "生成された順列は" << cn << "個です。" << endl;//←2026年3月19日訂正

              while (!_kbhit());//待機させるための命令

              return(0);

}

void f(int s) {

              int h;

              for (int i = 0; i < n; i++) {

                            if (s == 0)a[s] = i + 1;

                            h = 1;

                            if (s > 0) {

                                          for (int j = 0; j < s; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }

                                          if (h == 1)a[s] = i + 1;

                            }

                            if (h == 1) {

                                          if (s + 1 < n) {

                                                        f(s + 1);

                                          }

                                          else {

                                                        for (int j = 0; j < n; j++)cout << a[j];

                                                        cout << " ";

                                                        cn++;

                                                        if (cn % 10 == 0)cout << endl;

                                          }

                            }

              }

}

  s = 0 の場合

    
for (int i = 0; i < n; i++) {

      
if (s == 0)a[s] = i + 1; より a[0] = 1

                    h = 1;
                              ・
                              ・
                              ・

                            if (h == 1) {

                                          if (s + 1 < n) {

                                                        f(s + 1);

                                          }
 よりs = 1になり

 部屋番号1の世界に移動(昇華)
 
誰が、このf(1)の世界を呼び出したのでしょうか。f(0)です。
 後で図に訂正を加えますが、f(1)は呼び出されたときに初めて世界に生み出されます。
 もっと、正確に言うとメモリ上に登場します。
 図の訂正が必要なのはf(2)はまだ呼び出されておらずメモリ上に存在しません。

    for (int i = 0; i < n; i++) {

        からi = 0となるが、

                           h = 1;

                            if (s > 0) {

                                          for (int j = 0; j < s; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }

                                          if (h == 1)a[s] = i + 1;

                            }

                                          for (int j = 0; j < s; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }
             は

                                          for (int j = 0; j < 1; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }
             となりa[0]と i + 1 = 0 + 1 = 1が比較され

             if(a[0] == 1)が成立されて h = 0 となってしまい、

                            if (h == 1) {

                                          if (s + 1 < n) {

                                                        f(s + 1);

                                          }

                                          else {

                                                        for (int j = 0; j < n; j++)cout << a[j];

                                                        cout << " ";

                                                        cn++;

                                                        if (cn % 10 == 0)cout << endl;

                                          }

                            }は実行されません。それで、
    for (int i = 0; i < n; i++) の次に進み i = 1 となる。

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }の
                          a[j] == i + 1はa[0] == 2

                                                       if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }
                          は実行されずに h = 1 のままであり、
                                         if (h == 1)a[s] = i + 1;が実行され
                   a[1] = 2 となり、

             となります。

                            if (h == 1) {

                                          if (s + 1 < n) {

                                                        f(s + 1);

                                          }
             が実行され

             
部屋番号2の世界に移動(昇華)となります。
             誰が、f(2)を呼び出しのでしょうか。f(1)です。


                                         for (int j = 0; j < s; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }の重複検査をクリアできずに

              となりますが、これも

                                         for (int j = 0; j < s; j++) {

                                                        if (a[j] == i + 1) {

                                                                      h = 0;

                                                                      break;

                                                        }

                                          }の重複検査をクリアできずに、

             重複検査を初めてクリアして順列の1番目が生成されます。

             そして、

                            if (h == 1) {

                                          if (s + 1 < n) {

                                                        f(s + 1);

                                          }

                                          else {

                                                        for (int j = 0; j < n; j++)cout << a[j];

                                                        cout << " ";

                                                        cn++;

                                                        if (cn % 10 == 0)cout << endl;

                                          }

                            }
       
             の明るい紫部分によってコンソール画面にと打ち出されます。
 
             さて、f(2)のfor文はi = 0, i = 1,i = 2と最後まで展開が終わりました。

             するとどうなるのでしょうか。

void f(int s) {

              int h;

              for (int i = 0; i < n; i++) {

                           ・
                           ・
                           ・

              }

}

f(2)は任務を終了しています。

f(2)の運命はいかに?

答えは20行下に示します。






















〔解答〕

f(2)はメモリ上から消えます。

言い換えると
f(2)は消滅します。


部屋番号2 = 異世界2は消滅されこの世界にもはや存在していません。

関数は、任務を終了するとメモリから消滅するのでしたね。

図は

から

へと訂正されます。



などもすべて修正しようと考えましたが、

皆さんの頭の中で1と2の世界は点線に修正していただければと思います。

現在は存在していないが、

未来には存在する可能性があるということで頭の中で点線に修正してください。

尚、変数も関数も任務が終了すると消滅しますが、

int a[25]; //将来5次魔方陣まで生成できるように25に変更

int cn = 0; //anに変更 変更理由はnuberの頭文字nは整数を表す場合が多いからです。

の2つはグローバル配列とグローバル変数と言い、

プログラムが終了するまでメモリ上に存在します。

できるだけ単純な構成にして関数の再帰的方法をわかりやすくするという狙いがあります。

再帰的方法が皆さんが理解できた段階で両方とも引数にして送るつもりです。

つまり、グローバル配列とグローバル変数をやめる方針です。

メモリ節約の思想が必要だからです。

第9話はエクセルを使い手作業ですべての場合を考えることをします。



     






第9章第7話へ 第9章第9話へ

本講義トップへ