У меня есть внешняя коллекция, содержащая n элементов, которые я хочу выбрать из них (k) из них случайным образом, выведя индексы этих элементов в какой-то сериализованный файл данных. Я хочу, чтобы индексы выводились в строгом порядке возрастания, а для дубликатов не было. Как n, так и k могут быть довольно большими, и обычно нецелесообразно просто хранить целые массивы в памяти такого размера.Как сгенерировать список восходящих случайных целых чисел
Первый алгоритм, с которым я столкнулся, состоял в том, чтобы выбрать случайное число r [0] от 1 до nk ... и затем выбрать последовательные случайные числа r [i] из r [i-1] +1 в n -k + i, только нужно хранить две записи для «r» в любой момент времени. Однако довольно простой анализ показывает, что вероятность выбора небольших чисел не согласуется с тем, что могло бы быть, если бы весь набор был равномерно распределен. Например, если n был миллиардом и k составлял полмиллиарда, вероятность выбора первой записи с подходом, который я только что описал, очень крошечная (1 в пол-миллиарда), где на самом деле, поскольку половина записей выбранный, первый должен быть выбран в 50% случаев. Даже если я использую внешнюю сортировку для сортировки k случайных чисел, мне придется отбросить любые дубликаты и повторить попытку. Когда k приближается к n, количество попыток продолжит расти, без гарантии прекращения.
Я хотел бы найти алгоритм O (k) или O (k log k) для этого, если это вообще возможно. Язык реализации, который я буду использовать, - это C++ 11, но описания в псевдокоде могут по-прежнему быть полезными.
Генерируйте случайные целые числа как обычно (используя, например, 'std :: mt19937' и' std :: uniform_int_distribution') и сохраняйте результаты в 'std :: set', чтобы не было дубликатов, и в результате контейнер сортируется по своей сути. –
ArchbishopOfBanterbury
Всегда ли нужно выбирать точно k элементов? Или это приемлемо для того, чтобы средний счет многих прогонов стремился к k? Если последний, то просто добавьте RND (0, 2n/k) к каждой предыдущей записи, пока не дойдете до конца списка. –
Всегда восходящий. Нет хранения. Нет дублирования. Это трудно сделать. Мне придется подумать, возможно ли это. – user4581301