0

私はCプログラミングに非常に慣れておらず、if/else、ループ、配列、ポインター、関数、および構造体のみを行っています。時間とともにランダム化された値を含むが、2回しか繰り返されない値を持つ2次元配列を作成する方法を誰かが教えてくれたらとてもうれしいです...

たとえば、次のような意味です。

1 2 3 6
8 7 4 5
7 5 6 3
2 1 4 8

実際には、配列を6x6にする必要がありますが、これまでのところ、機能しないこの段階に来ています:

int x,y;
int i,j;

srand (time(NULL));

for ( x=0 ; x<6 ; x++){
    for ( y=0 ; y<6 ; y++) {
        sBoard[x][y] = rand() %36;          /*randomization*/

        for ( i=0 ; i<6 ; i++){  /*trying to create an unique array*/
            for ( j=0 ; j<6 ; j++) {
                if ((sBoard[x][y] == sBoard[i][j])) {
                    x--;
                    y--;
                }
            }
        }
        printf ("%i",sBoard[x][y]);
    }
    printf("\n");
}

================================================== =================================私の講師は私にIF関数を使用してチェックするように頼んだ値がマトリックスの他の場所で繰り返されているかどうか...そのため、「if」を使用しています...助けていただければ非常に感謝しています...よろしくお願いします...

4

4 に答える 4

1

問題は、if-then ブロックがまだそのレベルの一意性を保証していないことです。これを正しく機能させるには、while ループが必要です。この while ループは、理論的には決して終了しない可能性があり、(より可能性が高い) 実行するたびに実行にかかる時間が大幅に異なります。

はるかに簡単なのは、2 次元配列にすべての値を入力してから、それをシャッフルすることです。チートして 1 次元配列として扱うこともできますが、それでも同じように機能します。ここにいくつかの疑似コードがあります:

pointer-to-array pArray;
for i = 0 to 35
    pArray[i] = i
numShuffle = 2;
for s = 1 to numShuffle
    for i = 0 to 35
        swap pArray[i] with pArray[random 0 to 34 - if equal, add 1]

これにより、重複が存在しないことが保証され、コードの実行には常にまったく同じ時間がかかります (上記の while ループが終了しない可能性はありません)。

numShuffle を 1 に設定すると、良好な結果が得られる場合があります。これが真であることがわかった場合、その外側のループは必要ありません。

于 2010-11-03T09:27:32.923 に答える
0

許可される値の範囲はどれくらいですか?それが大きすぎず、いくつかのNであると仮定すると、次のアルゴリズムを提案します。

  • seen各値が生成された回数を指定して、N個のintカウンターの配列として初期化します。
  • ターゲットの2D配列に目を通し、で数値numを生成しrandます。
    • が2の場合seen[num]、再生成numして再試行してください
    • それ以外の場合は、2Dアレイのスロットに増やしseen[num]て配置しますnum

当然、seenすべてゼロで初期化する必要があります。

数値の範囲が大きい場合(たとえば、整数の範囲全体)、seen配列の代わりにハッシュテーブルを使用します。

于 2010-11-03T09:21:33.533 に答える
0

私は次のことについて少し混乱しています: 2d-array は (a) 特定の値を最大値として 2 回含むことを許可されていますか、それとも (b) 2d-array は各値を常に正確に 2 回保持する必要がありますか?

(a): 許可されたすべての値をそれぞれ 2 回保持するヘルパー配列を構築します。次に、このヘルパー配列のインデックスとして乱数を生成して、その中の数値の 1 つを選択し、目的の 2D 配列の「次の」位置に格納します。選択した値をヘルパー配列から削除することを忘れないでください。

(b): 最初は、1 から 18 までのすべての値をそれぞれ 2 回保持する 6x6 配列を作成できました。次に、反復ごとに 2 つの値を交換して値をシャッフルします。

編集:あなた自身のアプローチと他のいくつかの解決策の提案について:試行錯誤のアプローチは、すべての値が(2回だけ)保存されることを保証する最良の方法ではないと思います。理論的には、無限ループになる可能性があるためです。はい、私は知っています、これが起こる可能性は低いですが、私の意見では、とにかく少し汚いです. 不必要な操作を防ぐ決定論的/一定の実行時間を持つソリューションを好むでしょう。

于 2010-11-03T09:27:04.640 に答える
0

まず第一に、ランダムはそれ自体で繰り返しを排除するものではないということです。ランダムな分布はまさにランダムであり、アイテムが再び発生しないことを意味する均等に分散されたセットはありません。したがって、(簡単にするために) 6x6 の 2 次元配列を 36x 1 次元配列にフラット化し、後で再編成することから始めます。

そのため、1 次元配列を使用してループし、位置ごとに do ループで乱数を生成すると、0 から現在の位置まで既存の配列を反復処理する内部 for ループを作成できます。乱数がそれらの位置の 1 つで見られる場合は、フラグをマークして、それが既に見られていることを示します。そうすれば、「while(notUnique)」で do ループを終了できます。

わかりました - コードを見せてください!

int board1d[36];
int pos;
for(pos = 0; pos < 36; pos ++) {
  int newRand;
  int notUnique;
  do {
    int innerPos;
    notUnique = 0;
    newRand = rand() % 36;
    for(innerPos = pos; innerPos > 0 && notUnique==0; innerPos--) {
      notUnique = (newRand == board1d[innerPos]);
    }
  } while(notUnique);
  board1d[pos] = newRand;
}

これは、前述のように、ランダム ジェネレーターが繰り返されるシーケンスを生成する場合、ループがより多くのサイクルを必要とすることを潜在的に意味します。ランダムなセットでは、均等な分布が保証されていません。

于 2010-11-03T09:29:39.260 に答える