Вам нужно сгенерировать М равномерно распределенных случайных чисел из диапазона [0, N), но здесь есть одна оговорка.
Следует отметить, что ваше изложение проблемы неоднозначно. Что подразумевается под равномерно распределенным выбором? Одна вещь состоит в том, чтобы сказать, что каждый индекс должен быть выбран с равной вероятностью (конечно, M / N). Другое дело, что каждая двухиндексная комбинация должна выбираться с равной вероятностью. Эти два не одно и то же. Какой из них вы имели в виду?
Если M значительно меньше, чем N, классическим алгоритмом для выбора чисел M из диапазона [0, N) является алгоритм Боба Флойда, который можно найти в книге Бентли "Programming Peals". Это выглядит следующим образом (эскиз)
for (int j = N - M; i < N; ++j) {
int rand = random(0, j); // generate a random integer in range [0, j]
if (`rand` has not been generated before)
output rand;
else
output j;
}
Чтобы реализовать проверку того, был ли rand
уже сгенерирован или нет для относительно высокого M, необходима какая-то реализация набора, но в вашем случае M = 2 это просто и легко.
Обратите внимание, что этот алгоритм равномерно распределяет наборы из M чисел. Кроме того, этот алгоритм требует ровно M итераций (попыток) для генерации M случайных чисел, то есть он не следует за ошибочным подходом «проб и ошибок», часто используемым в различных специальных алгоритмах, предназначенных для решения одной и той же проблемы.
Адаптируя вышеизложенное к вашей конкретной ситуации, правильный алгоритм будет выглядеть следующим образом
first = random(0, N - 2);
second = random(0, N - 1);
if (second == first)
second = N - 1;
(я опускаю внутренние детали random(a, b)
как детали реализации).
Может быть не сразу понятно, почему вышеприведенное работает правильно и дает действительно равномерное распределение, но это действительно так:)