Python 随机数标准库(2) -- shuffle()

Python random包可以用来生成随机数。随机数不仅可以用于数学用途,还经常被嵌入到算法中,用以提高算法效率,并提高程序的安全性。如果想要更加高级的数学功能,可以考虑选择标准库之外的numpyscipy项目,它们不但支持数组和矩阵运算,还有丰富的数学和物理方程可供使用。

本章节主要介绍random.shuffle(),也叫做洗牌函数,它被用来打乱列表元素的顺序。

洗牌的意义

现实生活中有不少需要洗牌算法的场景。

  • 扑克牌
  • 音乐播放器

扑克牌游戏中,每轮游戏开始前都需要洗牌,使每个人摸到每张牌的概率尽量相等,确保游戏的公平性,同时增加游戏的随机性。

音乐播放器一般会提供“单曲循环”、“列表循环”、“随机播放”等多种播放模式。有不少用户偏好随机播放,著名音乐播放产品iPod Shuffle的卖点之一就是“你永远不知道你将要听到的下一首歌曲是什么”。

随机播放可以有两种实现方案: randomshuffle

名称 原理 优点 缺点
random 每次随机取歌播放 歌曲选取等概 可能出现AA、ABAB、ABCABC这种反人脑随机认知的序列
shuffle 按乱序列表顺序播放 避免random的缺陷 每轮播放中同一首歌只能出现一次

shuffle算法原理

Knuth-Durstenfeld Shuffle

Knuth-Durstenfeld ShuffleFisher-Yates shuffle的基础上对算法进行了改进,形成了现代工业界常用的洗牌算法。

Durstenfeld's solution is to move the "struck" numbers to the end of the list by swapping them with the last unstruck number at each iteration.

Durstenfeld的方法是:

  1. 每次从未乱序列表中随机选择一个数字
  2. 把该数字与未乱序列表的末尾数字交换,如此做则末尾存放的是已乱序处理过的数字
  3. 循环,直至所有数字均被乱序处理过

这是一个in-place的算法,算法时间复杂度从Fisher算法的O(n^2
)
提升到了O(n)。算法伪代码如下:

-- To shuffle an array a of n elements (indices 0..n-1):
for i from n−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

Python Random标准库中的shuffle使用的正是Knuth-Durstenfeld Shuffle算法。

def shuffle(self, x, random=None):
    """x, random=random.random -> shuffle list x in place; return None.
    Optional arg random is a 0-argument function returning a random
    float in [0.0, 1.0); by default, the standard random.random.
    """
    if random is None:
        random = self.random
    _int = int
    for i in reversed(xrange(1, len(x))):
        # pick an element in x[:i+1] with which to exchange x[i]
        j = _int(random() * (i+1))
        x[i], x[j] = x[j], x[i]

蓄水池算法

蓄水池算法从某种意义上来说,是另一种形式的shuffle算法。它能够从未知或者很大样本空间随机地取k个数,且保证样本空间中每一个数被抽取的概率是等概的。

在实际应用中,往往会遇到大数据流的情况。因此,我们无法先保存整个数据流然后再从中选取,而是期望有一种算法能将数据流遍历一遍就得到所选取的元素,并且保证得到的元素是随机的。这种算法正是蓄水池算法。

蓄水池算法的伪代码如下:

Init : a reservoir with the size: k
    for i= k+1 to N
        M=random(1, i);
        if (M < k)
             SWAP the Mth value and ith value
    end for

算法的核心思想分为两步:

  1. 构建一个容积为k的蓄水池,即对一个数据流的前k个元素,保存在集合A中;
  2. 从第k+1个元素开始,假设当前元素为数据流中的第m(m>k)个元素。先以 k/m的概率选择第m个元素,如果被选中,则从集合A中随机选择一个元素并用元素m替换之;否则淘汰元素m。

下面给出每个元素被选中的概率为k/n的证明:
设某元素m,且 m <= n,那么P(m最终被选中) = P(m被选中) * [P(m后面的元素没有被选中) + P(m后面的元素被选中) * P(m没有被替换)],即:

证明

拓展阅读

更多精彩内容,请关注我的个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容