洗牌算法

来源:互联网 发布:智多星定额造价软件 编辑:程序博客网 时间:2024/06/06 23:18

题目:

给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。

分析:

首先54张牌分别用0到53 的数值表示并存储在一个整形数组里,数组下标代表纸牌所在的位置。接下来,遍历整个数组,在每遍历一个数过程中随机产生一个随机数,并以该随机数为下标的数组元素与当前遍历到的数组元素进行对换。时间复杂度为O(n) 。

随机数的生成可以用<stdlib.h>中的rand实现,在调试过程中,发现每次运行后的随机数都是一样的。

因为rand的内部实现是用线性同余法做的,不是真的随机数,只不过是因为其周期特别长,所以在一定的范围里可看成是随机的,rand()会返回一随机数值,范围在0至RAND_MAX 间。RAND_MAX的范围最少是在32767之间(int),即双字节(16位数)。若用unsigned int 双字节是65535,四字节是4294967295的整数范围。  0~RAND_MAX每个数字被选中的机率是相同的。在调用此函数产生随机数前,必须先利用srand()设好随机数种子,如果未设随机数种子,rand()在调用时会自动设随机数种子为1。rand()产生的是假随机数字,每次执行时是相同的。若要不同,以不同的值来初始化它。初始化的函数即为srand()。 

按照上述表达重新整理如下:

函数一:int rand(void)。

函数二:void srand(unsigned seed); 从srand (seed)中指定的seed开始,返回一个【seed, RAND_MAX(0x7fff)】间的随机整数。

参数seed是rand()的种子,用来初始化rand()的起始值。

rand()在每次被调用的时候,它会查看srand(seed)

1) 如果用户在此之前调用过srand(seed),给seed指定了一个值,那么它会自动调用srand(seed)一次来初始化它的起始值。

2) 如果用户在此之前没有调用过srand(seed),它会自动调用srand(1)一次。

根据上面的第一点我们可以得出:

1) 如果希望rand()在每次程序运行时产生的值都不一样,必须给srand(seed)中的seed一个变值,这个变值必须在每次程序运行时都不一样。

2) 否则,如果给seed指定的是一个定值,那么每次程序运行时rand()产生的值都会一样,虽然这个值会是【seed, RAND_MAX(0x7fff)】之间的一个随机取得的值。

3) 如果在调用rand()之前没有调用过srand(seed),效果将和调用了srand(1)再调用rand()一样(1也是一个定值)。

在代码中,加入srand(time(0));即可解决此问题。time(0)表示从1970年1月1日00:00:00所经过的秒数。

完整代码如下:

#include <stdio.h>#include <time.h>#include <stdlib.h>void shuffle(int boke[])  //洗牌{int i,r,t;srand((unsigned)time(NULL)); //随机数种子,或者srand(time(0));for(i=0; i<54; i++){r=(rand()%107)/2;//交换t=boke[i];boke[i]=boke[r];boke[r]=t;}}int main(){int boke[54],i;for(i=0;i<54;i++) //初始化纸牌boke[i]=i;printf("before shuffle:\n");for(i=0; i<54; i++)    //打印printf("%d ",boke[i]);shuffle(boke);     //洗牌printf("\nafter shuffle:\n");for(i=0; i<54; i++)   //打印printf("%d ",boke[i]);return 0;}



0 0