Существует алгоритм, занимающий O(sqrt(N))
пробел и O(N)
время для односвязного списка.
Он не генерирует равномерное распределение повся последовательность перестановок, но она может дать хорошую перестановку, которую нелегко различить.Основная идея аналогична перестановке матрицы по строкам и столбцам, как описано ниже.
Алгоритм
Пусть размер элементов равен N
и m = floor(sqrt(N))
.Предполагая, что «квадратная матрица» N = m*m
сделает этот метод более понятным.
На первом проходе вы должны хранить указатели элементов, разделенных каждым m
элементом, какp_0, p_1, p_2, ..., p_m
.То есть p_0->next->...->next(m times) == p_1
должно быть истинным.
Перестановка каждой строки
- Для i = от 0 до m:
- Индексировать всеэлементы между
p_i->next
до p_(i+1)->next
в списке ссылок массивом размером O(m)
- Перемешать этот массив стандартным методом
- Повторное связывание элементов с использованием этого перемешанного массива
Перестановка каждого столбца.
- Инициализация массива
A
для хранения указателей p_0, ..., p_m
.Используется для обхода столбцов - Для i = 0 до m сделать
- Индексировать все элементы, отмеченные
A[0], A[1], ..., A[m-1]
в списке ссылок, массивом размером m
- Перемешать этот массив
- Повторно связать элементы с помощью этого перемешанного массива
- Переместить указатель на следующий столбец
A[i] := A[i]->next
Обратите внимание, что p_0
- это элемент, указывающий на первый элемент, а p_m
- на последний элемент.Кроме того, если N != m*m
, вы можете вместо этого использовать m+1
для некоторых p_i
.Теперь вы получаете «матрицу», такую, что p_i
указывают на начало каждой строки.
Анализ и случайность
Сложность пространства: для этого алгоритма требуется O(m)
место для хранения начала строки.O(m)
пространство для хранения массива и O(m)
пространство для хранения дополнительного указателя во время перестановки столбцов.Следовательно, временная сложность составляет ~ O (3 * sqrt (N)).Для N = 1000000
это около 3000 записей и 12 кБ памяти .
Сложность времени: очевидно, O(N)
.Он либо проходит по «матрице» строка за строкой, либо столбец за столбцом
Случайность: первое, на что нужно обратить внимание, это то, что каждый элемент может перейти в любое место матрицы по перестановке строк и столбцов,Очень важно, чтобы элементы могли попасть в любое место в связанном списке.Во-вторых, хотя он не генерирует все последовательности перестановок, он генерирует их часть.Чтобы найти число перестановок, мы предполагаем N=m*m
, каждая перестановка строк имеет m!
, и есть m рядов, поэтому мы имеем (m!)^m
.Если в столбец также включена перестановка, он в точности равен (m!)^(2*m)
, поэтому получить ту же последовательность практически невозможно.
Настоятельно рекомендуется повторить вторуюи третий шаг по меньшей мере еще один раз, чтобы получить более случайную последовательность.Потому что он может подавить почти всю корреляцию строк и столбцов к своему первоначальному расположению.Это также важно, когда ваш список не является «квадратным».В зависимости от ваших потребностей, вы можете использовать еще больше повторений.Чем больше повторений вы используете, тем больше перестановок и тем более случайным.Я помню, что можно сгенерировать равномерное распределение для N=9
, и я предполагаю, что можно доказать, что когда повторение стремится к бесконечности, оно совпадает с истинным равномерным распределением.
Править: сложность времени и пространства тесно связана и практически одинакова в любой ситуации.Я думаю, что это потребление пространства может удовлетворить ваши потребности.Если у вас есть какие-либо сомнения, вы можете попробовать это в небольшом списке, и я думаю, что вы найдете это полезным.