VBA洗牌法原理谁能文字阐释一下

VBA洗牌法原理谁能文字阐释一下,第1张

我找了此资料,一起共享

下面直接介绍经典数组洗牌法的算法原理:

假如你有一个布袋或者抽屉,里面有m=10个不同号码的球,

你要随机抽取,并保证不重复……

那么正确的做法是:

1 每次从布袋中随机抽取一个球; 注意到rnd()函数的正确抽取目数应该是=m

2 抽取出来的这一个球要另外放置开;

如果不另外放置,而只是记下号码后再把球返回布袋,接下来就无法保证这个已经被抽到过的球又被重复抽到。

而这个,就是1楼代码中没有考虑到而产生的重大bug

3 继续从布袋中随机抽取另一个球; 

注意到此时布袋中剩余球的数量少了一个是m-1了,因此rnd()函数的正确抽取目数应该是=m-1

4 抽取出来的这第2个球和已经抽取出来的第1个球放置在一齐,并且按新的序列排放。

5 重复以上随机抽取过程,注意到关键是:

a 每次抽取的母数即剩余球数要递减1个

b 每次抽取出来的新球要分开放置,不能放回布袋!

c 新抽取出来的球,要和前面已经取出的球按新的序列整齐排放。

   d 剩下最最重要一点,但是看到这里好多人都可能不会意识到的一个问题:

布袋中剩余球如何放置?

即,假定布袋中球也是像放置在抽屉中那样,有序地排放着的,

那么每次抽走一个球,必然留下一个空格……这就很麻烦了!

因为大家知道,实际上数组中用rnd()函数只能是返回一个一定区间内的值及数组位置

而如果留有空位的话,随机性就无法保证高效……万一抽到空格怎么办?难道重新再抽一次?

如果抽到只剩最后一个求时,则原先的布袋/抽屉中,将留下9个空格,则每次随机函数的计算结果,将有90%的概率仍旧抽到空格……

这就完蛋了。

经典数组洗牌法的真正原理是:

1 从m个值中随机确定一个位置r (利用Rnd()随机函数计算,具体算法是以剩余数m为母数区间进行随机值计算并取整返回位置)

2 把这个位置即要被抽取的元素(球)先取出拿在手中存入临时变量t,腾出一个空位。

3 把数组的第1位置(Lbound)元素拿出来,放入刚才腾出的r空位。并随即腾出了数组第一位置作为新的空位

(也可以以数组的最末位置(UBound)作为开始位置进行处理,具体算法代码就不太一样了)

4 把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入新的空位,即数组第一位置。

这个数组第一位置中的新元素,就是已经被有效抽取的第1个不重复值。

然后,继续

1 抽第2个数时,以剩余母数m-1作为随机计算区间而返回一个随机值并计算取整返回第2个不重复的随机位置r

2 把这个位置r即要被抽取的第2个元素(球)先取出拿在手中存入临时变量t,腾出一个空位。

3 把数组的第2位置元素拿出来,放入刚才腾出的r空位。并随即腾出了数组第2位置作为新的空位

(也可以以数组的最末倒数第2位置进行处理,具体算法代码就不太一样了)

4 把上述第2步骤取出的、存入了临时变量t的元素(球),准确地放入新的空位,即数组第2位置。

这个数组第2位置中的新元素,就是已经被有效抽取的第2个不重复值。

以上述方式反复进行,抽取、置换,存放,直到最后一个,也不会产生重复抽取了。

下面是经典数组洗牌法实际代码中最简单的代码例子:

对于一个下标1开始的一维数组,从中随机抽取n个元素返回。

Sub GetRnd(arr, n)

    Randomize

    For i = 1 To n  '正序洗牌 1 to n 简化代码

        r = Int(Rnd()  (n - i + 1)) + i

        t = arr(r): arr(r) = arr(i): arr(i) = t '下标1开始一维代码

    Next

End Sub

'正序洗牌 1 to n 简化代码详解:

Sub GetRnd(arr, n)

  Randomize '随机种子初始化,保证每次代码运行或打开文件时出现的随机序列是和上次文件保存/运行时不同的序列。

  For i = 1 To n  '遍历1 to n

r = Int(Rnd()  (n - i + 1)) + i  、

'按每次剩余母数(n - i + 1) 作为随机计算区间,计算Rnd()  (n - i + 1) 然后用int()函数去整,得到剩余数中的随机位置。

'紧接着,这个随机位置后面+i处理,转化成从新的起点i开始的随机位置r。即不再包括已经抽取出的结果,避免重复。

       t = arr(r) '把这个随机位置r中的元素取出,存入临时变量t

       arr(r) = arr(i) '把第i个位置中的元素放入刚才腾出的r空位(实际数据 *** 作时并没有腾出,而只是用新的值直接覆盖掉。)

       arr(i) = t '把上面刚刚腾出的i空位放入刚才存放在临时变量t中的当前最新抽取元素,完成一次抽取过程。

  Next  '循环抽取、置换、存贮抽取结果

End Sub

#include <stdioh>

#include <stdlibh>

#include <timeh>

int main()

{

int poke[13][4],joker[2],last_four_card[4]; //定义四类十三张牌、双王

int i,j,card,count,tank[54],player[20],computer[2][20];

bool flag;

srand(time(NULL)); //初始化随机种子

for(i=0;i<54;i++)

tank[i]=-1; //初始化容器

for(i=0;i<54;i++)

{

flag=1;

while(flag)

{

flag=0;

card=rand()%54;

for(j=0;j<=i;j++)

if(card==tank[j]) flag=1;

}

tank[i]=card;

}

count=0;

for(i=0;i<54;i++)

{

if(tank[i]==52) printf("jok ");

else if(tank[i]==53) printf("JOK ");

else if(tank[i]%13==0) printf("%c%c ",tank[i]/13+3,'A');

else if(tank[i]%13==10) printf("%c%c ",tank[i]/13+3,'J');

else if(tank[i]%13==11) printf("%c%c ",tank[i]/13+3,'Q');

else if(tank[i]%13==12) printf("%c%c ",tank[i]/13+3,'K');

else if(tank[i]%13<10) printf("%c%-2d ",tank[i]/13+3,tank[i]%13+1);

count++;

if(count%20==0) printf("\n");

}

count=0;

for(i=0;i<16;i++)

{

player[i]=tank[i];

computer[0][i]=tank[i+16];

computer[1][i]=tank[i+32];

}

for(i=0;i<4;i++)

last_four_card[i]=tank[53-i];

printf("\n\n你的牌是:\n\n");

for(i=0;i<16;i++)

{

if(player[i]==52) printf("jok ");

else if(player[i]==53) printf("JOK ");

else if(player[i]%13==0) printf("%c%c ",player[i]/13+3,'A');

else if(player[i]%13==10) printf("%c%c ",player[i]/13+3,'J');

else if(player[i]%13==11) printf("%c%c ",player[i]/13+3,'Q');

else if(player[i]%13==12) printf("%c%c ",player[i]/13+3,'K');

else if(player[i]%13<10) printf("%c%-2d ",player[i]/13+3,player[i]%13+1);

count++;

if(count%20==0) printf("\n");

}

getchar();

getchar();

return 0;

}

以前无聊写的 给你作参考吧

import javautilHashMap;

import javautilMap;

import javautilRandom;

/

Author:danagao

java 发牌程序,

不含大王,小王

可设定发牌人数

/

public class Pai {

HashMap<String, String> map = new HashMap<String, String>();

private static final String[] colors = {"红桃", "方块", "梅花", "黑桃"};

private static final String[] values = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};

private String[] newpai; private int len;

//初始化52张牌

public Pai() {

len = colorslength valueslength;

newpai = new String[len];

int k = 0;

for (int i = 0; i < colorslength; i++) {

for (int j = 0; j < valueslength; j++) {

newpai[k] = colors[i] + values[j];

k++;

}

}

}

//洗牌(把牌打乱)

private void getNums() {

Random r = new Random();

int i = rnextInt(len);

String s;

if (i >= 0 && !mapcontainsKey(StringvalueOf(i))) {

s = StringvalueOf(i);

mapput(s, newpai[i]);

} else {

getNums();

}

}

//发牌

public void showResult(int p) {

for (int i = 0; i < len; i++) {

getNums();

}

int l = len/p; //每人发几张牌

int j=1;//计人数

int k=0;//计牌数

for (MapEntry<String, String> entry : mapentrySet()) {

if(k%l==0 && j<=p){

Systemoutprintln("第"+j+"个人的牌:");

j++;

} else if(len-k <= len%p){

Systemoutprintln("剩余的牌:");

}

k++;

Systemoutprintln(entrygetValue());

} }

public static void main(String[] args) {

DbColorBall dbColorBall = new DbColorBall();

dbColorBallshowResult(4);

}

}

分类: 电脑/网络 >> 程序设计 >> 其他编程语言

解析:

用随机函数来模拟比较合适

扑克牌有54张,可以先约定好,比如:

大猫----------0

小猫----------1

黑桃A---------1

黑桃2---------黑桃A + 1

黑桃3---------黑桃A + 2

黑桃K---------黑桃A + 12

红心A---------黑桃A + 13

红心2---------红心A + 1

这样就可以把整副扑克牌的每张牌用一个特定的整数来表示,它们之间的大小关系可以通过不同的玩法制定相应的规则。

那好,现在我们定义一副牌int Joker[54];

用随机函数来填充Joker。

算法为:(不是真实的程序语言,由于不知道你使用什么编程语言,这里只描述算法)

for(i = 0 to 53)

{

l1:

生成随机数:pai = rand(54); 随机生成一个0 -- 53的整数

在已产生的牌中查找是否存在pai(即在Joker[0] 到Joker[i - 1]中查找)

如果存在,goto l1;

否则Joker[i] = pai

}

这样我们就把整副牌给洗好了。

接下来,就可以发牌了。

发牌时,只要按顺序把牌“发”到每个人的“手”里就行了

例如:4个人玩牌,四个人的牌为player[4][14];

for(i = 0 to 53)

{

player[i % 4][i / 4] = Joker[i];

}

这样就完成了发牌程序。

当然,如果你想要发牌也用一维数组,那也简单,比如还是4个人玩,那么:

player0手上的第n张牌就是Joker[n 4 + 0]

player1手上的第n张牌就是Joker[n 4 + 1]

player2手上的第n张牌就是Joker[n 4 + 2]

player3手上的第n张牌就是Joker[n 4 + 3]

好了,洗牌和发牌都已经完成,剩下就是如何玩牌了,你没问,就不多说了。

上面的伪代码应该能看懂吧?如果有问题,就用消息联系好了。你自己用编程语言去实现,不是什么大问题的。

以上就是关于VBA洗牌法原理谁能文字阐释一下全部的内容,包括:VBA洗牌法原理谁能文字阐释一下、编写C语言程序,模拟将一副扑克牌54张随机分给4个人 (如何表达不同花色和大小,如何高效洗牌)、java编写扑克牌游戏里,洗牌时发牌时用到了随机分配的功能,请问在那个包中哪个类哪个方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/9268667.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-26
下一篇 2023-04-26

发表评论

登录后才能评论

评论列表(0条)

保存