Если вы выбираете M
элементов из N
, стратегия меняется в зависимости от того, имеет ли M
тот же порядок, что и N
или намного меньше (т.е. меньше, чем N / log N).
Если они похожи по размеру, то вы проходите каждый пункт от 1
до N
.Вы отслеживаете, сколько предметов у вас так далеко (давайте назовем это m
предметов, выбранных из n
, через которые вы прошли), а затем вы берете следующее число с вероятностью (M-m)/(N-n)
и выбрасываете егоиначе.Затем вы обновляете m
и n
соответствующим образом и продолжаете.Это алгоритм O(N)
с низкими постоянными затратами.
Если, с другой стороны, M
значительно меньше, чем N
, тогда стратегия повторной выборки является хорошей.Здесь вы захотите отсортировать M
, чтобы вы могли быстро найти их (и это будет стоить вам O(M log M)
времени - например, вставьте их в дерево).Теперь вы равномерно выбираете числа от 1
до N
и вставляете их в свой список.Если вы обнаружите столкновение, выберите снова.Вы столкнетесь примерно в M/N
времени (на самом деле, вы интегрируете от 1 / N до M / N), что потребует от вас выбора (рекурсивно), поэтому вы ожидаете, что M/(1-M/N)
выборазавершить процесс.Таким образом, ваша стоимость этого алгоритма составляет примерно O(M*(N/(N-M))*log(M))
.
Это оба таких простых метода, которые вы можете просто реализовать оба - при условии, что у вас есть доступ к отсортированному дереву - и выбрать тот, который подходитс учетом доли чисел, которые будут выбраны.
(Обратите внимание, что сбор чисел симметричен и не позволяет их выбирать, поэтому, если M
почти равен N
, то вы можете использовать стратегию повторной выборки, новыберите эти числа, чтобы включить , а не ; это может быть выигрышом, даже если вам нужно сдвинуть все почти-N
числа, если генерация случайных чисел стоит дорого.)