写一个随机洗牌函数——概率题

题目描述:

写一个随机洗牌函数。要求洗出的52!种组合都是等概率的。 也就是你洗出的一种组合的概率是1/(52!)。假设已经给你一个完美的随机数发生器。

解题思路:

这是一道概率题

随机洗牌,目的是要做到随机性,要求每一张牌出现的概率要相等.

我们常用的普通扑克牌54张,要做到每张牌出现的概率是1/(54!),

抽第一张牌概率:1/54;

抽第二张牌概率:1/53;

抽第三张牌概率:1/52;

……

一直这样随机地拿下去直到拿完最后1张,我们就从52!种可能中取出了一种排列, 这个排列对应的概率是1/(54!).

这正是题目所要求的,随机洗牌目的.

有了思路,接下来就是如何编码实现。

首先,我们有一个随机函数发生器,能够产生1-54之间的随机数,如何保证抽第一张牌是54中可能,抽第二张牌是53中可能,……

可以这样做,假设扑克牌是一个54维的数组card, 我们要做的就是从这个数组中随机取一个元素,然后在剩下的元素里再随机取一个元素… 这里涉及到一个问题,就是每次取完元素后,我们就不会让这个元素参与下一次的选取。

我们要实现的目的是以等概率的方式将这54个数随机打乱排列,因此,可以这样处理:

第一次抽牌在初始54张牌中,将 随机产生的牌x,与第一个元素互换,

第二次抽牌在剩下的53张牌中,将 随机产生的牌y,与第二个元素互换,

……

举个例子,假设10张牌,arr[] = {1,2,3,4,5,6,7,8,9,10},假定第一次产生的牌是6,那么接下来的操作就是:将6与1互换,之后在剩下的{2,3,4,5,1,7,8,9,10}中产生第二个牌. ……

参考代码:

#include <iostream>
#include <cstdlib>
using namespace std;

void Swap(int &a, int &b){// 有可能swap同一变量,不能用异或版本
    int t = a;
    a = b;
    b = t;
}

void SwapXOR(int &a, int &b)//异或版本的交换
{
       a = a^b;
       b = a^b;
       a = a^b;
}

void RandomShuffle(int a[], int n){
    for(int i=0; i<n; ++i){
        int j = rand() % (n-i) + i;// 产生i到n-1间的随机数
        Swap(a[i], a[j]);//交换位置
    }
}
int main(){
    srand((unsigned)time(0));//随机种子
    int n = 54;
    int a[] = {
        1, 2, 3, 4, 5, 6, 7, 8, 9,10,……,54
    };
    RandomShuffle(a, n);//调用洗牌函数
    for(int i=0; i<n; ++i)//输出一次洗牌效果
        cout<<a[i]<<endl;
    return 0;
}

参考资料:

1、http://www.cricode.com/2515.html

2、http://coolshell.cn/articles/8593.html

时间: 2024-08-25 16:46:38

写一个随机洗牌函数——概率题的相关文章

一个数组实现扑克牌均匀随机洗牌------多次洗牌能否避免黑客的计算?

闲来无事,研究下纸牌发牌,按斗地主来发吧,思路如下: 1,新建一个数组,长度52,将四种花色和大小王存储进数组 2,循环0至51,在循环因子i至52之间取随机数(能取到下界,不能取到上界),取到的随机数作为数组元素下标取该元素,与第i个元素交换位置,循环结束即排序完毕 3,输出纸牌即可. 思路明确,"啪啪啪~~" 12秒之后 贴上代码 1初始化数组 //声明存放纸牌的数组 string[] Card = new string[54]; //初始化四种花色和大小王,分别用▲★◆■+数字和

一步一步写算法(洗牌算法)

[ 声明:版权所有所有,欢迎转载.不用于商业用途. 联系我们:feixiaoxing @163.com] 扑克洗牌是我们的生命更喜欢玩游戏. 么我们有没有什么办法自己设计一个扑克牌洗牌的方法呢?在c执行库其中有一个随机函数rand,它能够生成0~32767之间的随意数.那么有没有可能利用这么一个函数对我们扑克牌进行随即洗牌呢? 在这里我抛砖引玉一下,谈一谈自己眼下已经看到的两个算法.欢迎朋友们谈一谈其它的方法. (1)全局洗牌法 过程例如以下所看到的: a)首先生成一个数组,大小为54,初始化为

随机洗牌算法

随机洗牌算法: 时间和空间复杂度都为O(n). 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 54; 6 7 void random_shuffle(vector<int> &a) 8 { 9 srand(int(time(0))); 10 int aSize = a.size(); 11 for(int i = 1; i != aSize; ++i) { 12 int j

随机洗牌算法Knuth Shuffle和错排公式

Knuth随机洗牌算法:譬如现在有54张牌,如何洗牌才能保证随机性.可以这么考虑,从最末尾一张牌开始洗,对于每一张牌,编号在该牌前面的牌中任意一张选一张和当前牌进行交换,直至洗到第一张牌为止.参考代码如下: void knuth() { for (int i = 54; i > 1; i--) { int id = rand() % (i - 1) + 1; swap(a[i], a[id]); } } 由上述方法可知,每一张牌经过洗牌之后一定不会出现在原来位置,那么一共会有多少情况呢,这其实就

集合综合练习(斗地主随机洗牌)

package com.zs.Demo; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class DouDiZhu { private static Map<Integer,String> Pooker; private static ArrayList<Integer> Pookervalue; pr

随机洗牌

一.随机数洗牌 //pArray 要打乱的数组 //uCount 数组长度 //uItemSize 数组中每个元素的大小 void CGameConvenient::Shuffle(void *pArray,ushort uCount,ushort uItemSize) { if(nCount<=1) return; //记录下标 std::vector<ushort> IndexArray;  //原数组 IndexArray.resize(uCount); for(ushort i=

如何随机洗牌一个数组

在使用javascript的时候有可能会有随机打乱一个数组的需求,我们可以利用数组的sort方法和Math.random来随机排序 const arr = [1,2,3]; arr.sort(() => 0.5 - Math.random()) console.log(arr) 主要利用了Math.random()生成随机数与0.5的大小比较来排序,如果0.5 - Math.random()大于或等于0,数组中的两个数位置不变,小于0就交换位置. 乍一看这样是达到了随机排序的效果,但是实际上这个

python写一个随机点名软件

最近有个随机点名软件的需求,故写了一个,上代码:github地址 # -*- coding: utf-8 -*- # @Time : 18-12-31 下午4:21 # @Author : Felix Wang from tkinter import * import tkinter.font as tkFont import random import gc import os, sys import chardet import copy from threading import Thre

像阿超那样,花20分钟写一个能自动生成小心四则运算题目的 “软件”,要求:除了整数以外,还要支持真分数的四则运算。 和同学们比较一下各自程序的功能,实现方法的异同,等等

package chapter; public class szys {    public static void main(String[] args)    { print30Questions();    }        private static void print30Questions()     {        //说明:打印30道题函数,把接收到的题目字符串按照指定格式输出.        for (int i = 0; i < 10; i++)        {