Вы ищете отклонение ваших записей.
Прежде всего, ваш алгоритм работает в том смысле, что он выводит случайное отклонение, то есть перестановку без фиксированной точки.Однако у него есть огромный недостаток (который вы можете не возражать, но стоит иметь в виду): некоторые нарушения не могут быть получены с помощью вашего алгоритма .Другими словами, это дает нулевую вероятность некоторых возможных отклонений, поэтому результирующее распределение определенно не является равномерно случайным.
Одним из возможных решений, как предлагается в комментариях, было бы использование алгоритма отклонения:
- выбрать случайную перестановку равномерно
- , если она не имеет фиксированных точек, вернуть ее
- в противном случае повторить попытку
Асимптотически, вероятность получениярасстройство близко к 1/e
= 0,3679 (как видно из статьи в Википедии).Это означает, что для получения расстройства вам нужно будет генерировать в среднем e
= 2,718 перестановок, что довольно дорого.
Лучший способ сделать это - отклонить на каждом шаге алгоритма.В псевдокоде, что-то вроде этого (если исходный массив содержит i
в позиции i
, то есть a[i]==i
):
for (i = 1 to n-1) {
do {
j = rand(i, n) // random integer from i to n inclusive
} while a[j] != i // rejection part
swap a[i] a[j]
}
Основное отличие от вашего алгоритма состоит в том, что мы разрешаем j
быть равным i
, но только если оно не дает фиксированной точки.Он немного дольше выполняется (из-за части отклонения) и требует, чтобы вы были в состоянии проверить, находится ли запись в ее первоначальном месте или нет, но у него есть то преимущество, что он может вызывать все возможные помехи (равномерно, для этоговопрос).
Я предполагаю, что должны существовать алгоритмы неприятия, но я бы посчитал их менее простыми.
Редактировать:
Мой алгоритм на самом деле плох: у вас все еще есть шанс закончить с последней точкой без перестановок, и распределение не является случайным, смотрите предельные распределения моделирования:
Алгоритм, который производитЗдесь можно найти равномерно распределенные отклонения здесь , с некоторым контекстом проблемы, подробными объяснениями и анализом.
Второе редактирование:
Собственно ваш алгоритмизвестен как алгоритм Саттоло и, как известно, производит все циклы с равной вероятностью.Таким образом, любое нарушение, которое не является циклом, но продуктом нескольких непересекающихся циклов, не может быть получено с помощью алгоритма.Например, с четырьмя элементами перестановка, которая обменивает 1 и 2, а также 3 и 4, является отклонением, а не циклом.
Если вы не возражаете против получения только циклов, то алгоритм Саттоло является способомна самом деле, это намного быстрее, чем любой алгоритм унифицированного расстройства, так как никакого отклонения не требуется.