伪随机数对大列表的完全性洗牌

对一个列表(一维数组)的完全性洗牌(shuffle)操作,是要让其元素每种排列模式等概率出现。

列表元素个数为n,那么其全排列的数目就是n的阶乘“n!”。

伪随机数是有周期的,设周期为m。那基于伪随机数映射的元素排列模式也只会有m种。

当列表元素很多,n! 会是个天文数字,大于伪随机数周期,那样永远有一部分排列模式无法出现。

python标准库函数random.shuffle(x)就说明了——“请注意,即使对于小的len(x),x的排列总数也可以快速增长,大于大多数随机数生成器的周期。 这意味着长序列的大多数排列永远不会产生。 例如,长度为2080的序列是可以在 Mersenne Twister 随机数生成器的周期内拟合的最大序列。”

要对大于伪随机数周期的大列表完全性shuffle,怎么办呢

我采用的办法是多轮洗牌,每轮用不同质数周期的伪随机数序列。这些周期的乘积大于列表元素全排列数目“n!”,就保证了完全性shuffle的完成。

我写了这个算法的实现python包,源码放在GitHub上,complete_shuffle

已经发布到了PyPI上,可以很方便的安装分发:

pip install complete-shuffle

此包还包括了Sattolo算法实现的对列表随机循环排列。算法介绍见Sattolo算法

等概率生成列表的“全错位排列”函数,功能实现了可以用于含重复元素的列表。我使用的是优化的接受-拒绝采样算法,时间复杂度为O(n)。生成均匀分布“全错位排列”还有一种优化算法,见Generating Random Derangements。此算法时间复杂度也是O(n),但声称其时间复杂度的常数项较低。我看意义不大。

顺便说python 3.9版已声明 random.shuffle() 的 random 形参将被弃用

我写这个包中函数就有等同于 random.shuffle() 的 random 的形参。可以替代标准库random.shuffle()函数了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章