Одним из самых быстрых способов сделать множество с заменой образцов из неизменного списка является метод псевдонима. Основная интуиция заключается в том, что мы можем создать набор бинов одинакового размера для взвешенного списка, который можно очень эффективно индексировать с помощью битовых операций, чтобы избежать двоичного поиска. Получится, что, если все сделано правильно, нам нужно будет хранить только два элемента из исходного списка на одну ячейку, и, таким образом, мы можем представлять разделение с одним процентом.
Давайте рассмотрим пример пяти одинаково взвешенных вариантов: (a:1, b:1, c:1, d:1, e:1)
Чтобы создать поиск псевдонимов:
Нормализуйте веса так, чтобы они суммировались до 1.0
. (a:0.2 b:0.2 c:0.2 d:0.2 e:0.2)
Это вероятность выбора каждого веса.
Найдите наименьшую степень 2, большую или равную количеству переменных, и создайте это число секций, |p|
. Каждый раздел представляет массу вероятности 1/|p|
. В этом случае мы создаем 8
разделов, каждый из которых может содержать 0.125
.
Возьмите переменную с наименьшим оставшимся весом и поместите как можно большую часть ее массы в пустой раздел. В этом примере мы видим, что a
заполняет первый раздел. (p1{a|null,1.0},p2,p3,p4,p5,p6,p7,p8)
с (a:0.075, b:0.2 c:0.2 d:0.2 e:0.2)
Если раздел не заполнен, возьмите переменную с наибольшим весом и заполните раздел этой переменной.
Повторяйте шаги 3 и 4 до тех пор, пока ни один из весов из исходного раздела не будет назначен списку.
Например, если мы выполним еще одну итерацию 3 и 4, мы увидим
(p1{a|null,1.0},p2{a|b,0.6},p3,p4,p5,p6,p7,p8)
с (a:0, b:0.15 c:0.2 d:0.2 e:0.2)
осталось назначить
Во время выполнения:
Получите U(0,1)
случайное число, скажем, двоичное 0.001100000
Сдвиг битов lg2(p)
, поиск индекса раздела. Таким образом, мы сдвигаем его на 3
, получая 001.1
, или позицию 1, и, таким образом, делим 2.
Если разделение разделено, используйте десятичную часть смещенного случайного числа, чтобы решить разделение. В этом случае значение равно 0.5
и 0.5 < 0.6
, поэтому верните a
.
Вот некоторый код и другое объяснение , но, к сожалению, он не использует технику битового сдвига, и я на самом деле не проверял ее.