配列のシャッフル

a[N] = { 1, 2, ..., N }

っていうのを並べ替えたい時は、以下のようにしてやると効率が良く、数学的にもどの順列も等確率で生成される事が証明できる。

for (i = 0; i < N; i++) {
    swap(a[i], a[i〜N-1のどれかをランダムに選ぶ]);
}

これが恐らく一番良い方法の一つなので覚えておくと良い。

で、本題。

for (i = 0; i < N; i++) {
    bool ok;
    v = 1〜Nの数をランダムに生成;
    do {
        ok = true;
        for (k = i - 1; k > 0; k--) {
            if (a[k] == v) {
                ok = false;
                break;
            }
        }
    } while (!ok);
    a[i] = v;
}

こんな風に書いちゃう大学生もいるんだけど、これは効率が悪い。頑張って計算してみたら平均\sum_{n=0}^{N-1}{\frac{N}{N-n}}回かかることがわかた。N=1000の時に平均7000回位なのでまぁ許せると言えば許せるけど、運ゲーなのでたまに恐ろしい時間はまってしまう危険性もある。と言うわけで最初に書いた方を使うようにしましょう。std::random_shuffleをつかっとけと。