作为背景,我知道 Fisher-Yates的完美洗牌。它的 O (n)复杂性和保证的一致性是一个很好的混乱,如果不在允许就地更新数组的环境中使用它,我就是一个傻瓜(如果不是所有的话,那么在大多数 势在必行编程环境中也是如此)。
遗憾的是,函数式编程世界不允许您访问可变状态。
然而,由于 Fisher-Yates 的缘故,我找不到太多关于如何设计洗牌算法的文献。实际上,少数几个提到这个问题的地方,在说出“这就是费舍尔-耶茨,你需要知道的所有洗牌方法”之前,都做了简短的说明。最后,我不得不想出自己的解决办法。
我提出的解决方案就是这样对任何数据列表进行洗牌:
在 Erlang 代码中,它看起来是这样的:
shuffle([]) -> [];
shuffle([L]) -> [L];
shuffle(L) ->
{Left, Right} = lists:partition(fun(_) ->
random:uniform() < 0.5
end, L),
shuffle(Left) ++ shuffle(Right).
(如果这看起来像是一个疯狂的快速排序,那么,基本上就是这样。)
So here's my problem: the same situation that makes finding shuffling algorithms that aren't Fisher-Yates difficult makes finding tools to 分析 a shuffling algorithm equally difficult. There's lots of literature I can find on analysing PRNGs for uniformity, periodicity, etc. but not a lot of information out there on how to analyse a shuffle. (Indeed some of the information I found on analysing shuffles was just plain wrong -- easily deceived through simple techniques.)
因此,我的问题是: 我如何分析我的洗牌算法(假设那里的 random:uniform()
调用能够产生具有良好特征的适当随机数) ?我有什么数学工具可以用来判断,比如说,对一个范围为1的整数列表进行100,000次洗牌。。100已经给了我似乎很好的洗牌结果?我自己做了一些测试(例如,比较洗牌中的增量和减量) ,但是我想知道更多。
如果有任何关于洗牌算法本身的见解,我们也会很感激。