C言語関係掲示板

過去ログ

No796 重複しない乱数値列

[戻る] [ホームページ]
No.9979

ランダム
投稿者---daidarosu(2003/10/24 15:49:34)


ループで1から10のランダムを使ってすべて表示したいとき、aにランダムな数値を入れます。
次にまた1から10の数値をランダムして入れる時、aには一回1の数値を入れてるのでいれたくありません。どうしたらいいですか?
1がきたらbに1がきたという数値を覚えておいてこないようにできますが、
運が悪ければずっとループしてしまいます。


No.9980

Re:ランダム
投稿者---YuO(2003/10/24 16:29:34)


>ループで1から10のランダムを使ってすべて表示したいとき、aにランダムな数値を入れます。
>次にまた1から10の数値をランダムして入れる時、aには一回1の数値を入れてるのでいれたくありません。どうしたらいいですか?

重複しない乱数値列は,通常採りうる値を並べた配列をシャッフルすることによって生成します。
void shuffle (int array[], int count)
{
    int i;
    for (i = 0; i < count; ++i) {
        int temp, target;
        target = rand() % count; /* サンプルなので下位ビットのランダム性に関する話は無視 */
        temp = array[i];
        array[target] = array[i];
        array[i] = temp;
    }
}


あとはこれを使えばできるかな?
#私が読みとれたのは,重複しない乱数値列が欲しそうだ,ということ。
#何がしたいのかはよくわからなかった……。


No.9981

Re:ランダム
投稿者---daidarosu(2003/10/24 16:43:01)


同じ数値がこないようにはどうしたらいいですか?
例えば
1、9、7、2、3、6、10、8、4、5
のように表示したいです。

No.9983

Re:ランダム
投稿者---YuO(2003/10/24 19:31:16)


>同じ数値がこないようにはどうしたらいいですか?
>例えば
>1、9、7、2、3、6、10、8、4、5
>のように表示したいです。

先のshuffleを使えばよいです。
配列に1〜10の値を入れてshuffleを呼び出せば,
配列がランダムに並び替えられるので,
あとはそれを出力するだけです。


No.9984

Re:ランダム
投稿者---daidarosu(2003/10/24 19:41:09)



>先のshuffleを使えばよいです。
>配列に1〜10の値を入れてshuffleを呼び出せば,
>配列がランダムに並び替えられるので,
>あとはそれを出力するだけです。

target = rand() % count
これって同じ数字は入らないのですか?


No.9985

Re:ランダム
投稿者---nop(2003/10/24 20:07:24)


>target = rand() % count
>これって同じ数字は入らないのですか?

並べ替えの時のインデックスとして使用しているため、
同じ値が出ても配列に入っている値に同じ値がなければ大丈夫です。

No.9987

Re:ランダム
投稿者---daidarosu(2003/10/24 21:23:59)


>>target = rand() % count
>>これって同じ数字は入らないのですか?
>
>並べ替えの時のインデックスとして使用しているため、
>同じ値が出ても配列に入っている値に同じ値がなければ大丈夫です。
Yuoさんnopさんありがとうです。

No.10012

Re:ランダム
投稿者---daidarosu(2003/10/25 16:27:12)


>同じ値が出ても配列に入っている値に同じ値がなければ大丈夫です。

てことは同じ値がずっと来ていたら処理の速さが変わるってことですか?

No.10016

Re:ランダム
投稿者---YuO(2003/10/25 16:47:05)


>>同じ値が出ても配列に入っている値に同じ値がなければ大丈夫です。
>てことは同じ値がずっと来ていたら処理の速さが変わるってことですか?

変わりません。

私の書いたshuffleに,繰り返しになる可能性があるものはfor一つです。
そして,ループ変数はインクリメントしかしていませんから,
実行にかかる時間はcountのみに比例します。


shuffleを現実世界で実行すると,
1. トランプのようにそれぞれを区別できるカードをcount枚用意して,横に並べる [array, countの定義・初期化]
2. 以下の試行をcount回繰り返す [for文]
2-a. count面体のサイコロを振る [target = rand() % count]
2-b. 左からi番目のカードと左から(2-aで出たサイコロの値)番目のカードを入れ替える [for文の最後三行]
 ただし,iは試行が行われた回数。
ということになります。

トランプのカード六枚と六面体のサイコロを用意して実際にやってみると,
何をしているのかがわかりやすくなるかもしれません。


No.10015

Re:ランダム
投稿者---daidarosu(2003/10/25 16:44:13)


void shuffle (int array[], int count)
{
int i;
for (i = 0; i < count; ++i) {
int temp, target;
   target = rand() % count; /* サンプルなので下位ビットのランダム性に関する話は無視 */
temp = array[i];
array[target] = array[i];
array[i] = temp;
}
}
質問です。temp = array[i]とarray[i] = temp;違いがわかりません。
もうすこし詳しく教えてください。お願いします。

No.10017

Re:ランダム
投稿者---YuO(2003/10/25 16:49:32)


> temp = array[i];
> array[target] = array[i];
> array[i] = temp;
>質問です。temp = array[i]とarray[i] = temp;違いがわかりません。

ぐはぁ……。
temp = array[i];
array[i] = array[target];
array[target] = temp;

が正しいです。

<言い訳>
普段,STL(C++)のstd::random_shuffleばっかり使っているから……
</言い訳>


No.10030

Re:ランダム
投稿者---daidarosu(2003/10/25 21:45:32)


>> temp = array[i];
>> array[target] = array[i];
>> array[i] = temp;
>>質問です。temp = array[i]とarray[i] = temp;違いがわかりません。
>
>ぐはぁ……。
>
temp = array[i];
array[i] = array[target];
array[target] = temp;

>が正しいです。
>
><言い訳>
>普段,STL(C++)のstd::random_shuffleばっかり使っているから……
></言い訳>

さっそく実行してみます。
ありがとうございました。

No.10027

Re:Re:ランダム
投稿者---ceybord(2003/10/25 20:10:03)


>>ループで1から10のランダムを使ってすべて表示したいとき、aにランダムな数値を入れます。
>>次にまた1から10の数値をランダムして入れる時、aには一回1の数値を入れてるのでいれたくありません。どうしたらいいですか?
>
>重複しない乱数値列は,通常採りうる値を並べた配列をシャッフルすることによって生成します。
><PRE>void shuffle (int array[], int count)
{
int i;
for (i = 0; i < count; ++i) {
int temp, target;
target = rand() % count; /* サンプルなので下位ビットのランダム性に関する話は無視 */
temp = array[i];
array[target] = array[i];
array[i] = temp;
}
}</PRE>
>
>あとはこれを使えばできるかな?
>#私が読みとれたのは,重複しない乱数値列が欲しそうだ,ということ。
>#何がしたいのかはよくわからなかった……。

これを見て思ったんですが、やっぱりC言語では配列の宣言を工夫しない限りは配列の長さを取得する関数は作れないのでしょうか?

No.10028

Re:Re:ランダム
投稿者---YuO(2003/10/25 20:48:25)


>これを見て思ったんですが、やっぱりC言語では配列の宣言を工夫しない限りは配列の長さを取得する関数は作れないのでしょうか?

どんなに工夫をしても,配列長を取得する関数を作成することは不可能です。


No.10069

Re:Re:Re:ランダム
投稿者---ceybord(2003/10/26 22:29:06)


>>これを見て思ったんですが、やっぱりC言語では配列の宣言を工夫しない限りは配列の長さを取得する関数は作れないのでしょうか?
>
>どんなに工夫をしても,配列長を取得する関数を作成することは不可能です。

少し説明が足りなかったようです。
私が考えたのは欠損値(たとえば文字型ならNUL,4バイト符号付整数型なら-2147483648のようにする。欠損値を何にするかはあらかじめ決めておく。)を配列の最後に付加して配列の長さを取得するというものです。
宣言時の工夫ではないですね。