考虑洗牌这件事

0x00 洗牌算法

对于一个N张卡片序列,最直接的最贴近等概率随机的方法是列出全部 N! 种可能(即N的全排列),从中随机抽取一种。显然这种方式的复杂度难以接受,一个简单的洗牌操作无法容忍这种等待时间和对工作空间的占用。
这里使用经典的Fisher-Yates算法,仅耗费O(1)空间和O(n)时间完成操作:

[Algorithm]
To shuffle an array a of n elements (indices 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer with 0 ≤ j ≤ i
       exchange a[j] and a[i]
[C]
void Shuffle_FisherYates(char *arr, const int len)
 {
      for(int i = len - 1; i > 0; i--)
     {
          int a = rand()%(i + 1);
          int temp = arr[i];
          arr[i] = arr[a];
          arr[a] =  temp;
      }
 }

0x01 随机数的产生

  • 从学C的第一堂课就知道的一件事:rand()函数所产生的伪随机数随机性能很差,即使加上了seed(一般是Time)也容易出现问题,如短时间内需要多次洗牌。这种情况虽然少见,但也需要加以考虑。
    MersenneTwister法看起来较为合适。

与其它已使用的伪随机数发生器相比,产生随机数的速度快、周期长,可达到2^19937-1,且具有623维均匀分布的性质,对于一般的应用来说,足够大了。

  • 对于小黑屋来说,最多的大概是房间和事件牌了,最大也不超过70张,目前看来这样的不重复空间已经足够使用了。
    尝试一次8骰的能力检定:
    13点,看起来运气不错。
image.png
#ifndef _MersenneTwister_H_
#define _MersenneTwister_H_

#include <ctime>
#include <stdint.h>
#include <math.h>

using namespace std;

typedef int32_t MS_INT;

class MersenneTwister
{
public:
    void rseed(MS_INT seed) {
        if (isInitialized) {
            return;
        }
        msInit(seed);
    }
    int rand(void) {
        if (isInitialized == false) {
            return 0;
        }
        return msRand();
    }
public:
    MersenneTwister(int seed) :isInitialized(0) {
        rseed(seed);
    }
    ~MersenneTwister() {

    }
    /* Initialize the generator from a seed */
    void msInit(int seed) {
        MS_INT i;
        MS_INT p;
        idx = 0;
        MT[0] = seed;
        for (i = 1; i < 624; ++i) { /* loop over each other element */
            p = 1812433253 * (MT[i - 1] ^ (MT[i - 1] >> 30)) + i;
            MT[i] = p & 0xffffffff; /* get last 32 bits of p */
        }
        isInitialized = 1;
    }

    /* Extract a tempered pseudorandom number based on the idx-th value,
    calling ms_generate() every 624 numbers */
    MS_INT msRand() {
        if (!isInitialized)
            msInit((MS_INT)time(NULL));

        if (idx == 0)
            msGenerate();

        MS_INT y = MT[idx];
        y = y ^ (y >> 11);
        y = y ^ ((y << 7) & 2636928640);
        y = y ^ ((y << 15) & 4022730752);
        y = y ^ (y >> 18);

        idx = (idx + 1) % 624; /* increment idx mod 624*/
        return y;
    }

    /* Generate an array of 624 untempered numbers */
    void msGenerate() {
        MS_INT i, y;
        for (i = 0; i < 624; ++i) {
            y = (MT[i] & 0x80000000) +
                (MT[(i + 1) % 624] & 0x7fffffff);
            MT[i] = MT[(i + 397) % 624] ^ (y >> 1);
            if (y % 2) { /* y is odd */
                MT[i] = MT[i] ^ (2567483615);
            }
        }
    }
private:
    MS_INT MT[624];
    MS_INT idx;
    MS_INT isInitialized;
};

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

推荐阅读更多精彩内容

  • 一、实验目的 学习使用 weka 中的常用分类器,完成数据分类任务。 二、实验内容 了解 weka 中 explo...
    yigoh阅读 8,547评论 5 4
  • 回溯算法 回溯法:也称为试探法,它并不考虑问题规模的大小,而是从问题的最明显的最小规模开始逐步求解出可能的答案,并...
    fredal阅读 13,667评论 0 89
  • 快到年底了,你回想下去年给今年定下的目标和计划,有几项已经完成了?我们大多数人都有这个缺点,希望学习一项技能或者做...
    成长最重要阅读 358评论 2 2
  • 前天晚上忽然特别想吃豆芽,虽说豆芽不是什么稀罕菜,但是我自己几乎不去菜场买它,原因大家都懂得....于是想买个豆芽...
    爱菲儿_008阅读 386评论 0 3
  • 别旬云笼山河深,旧春风细夜幽明。 新愁试问浑肠语,一抹烟波一抹情。
    鬼醉风阅读 278评论 13 51