当前位置:首页 » 操作系统 » c洗牌算法

c洗牌算法

发布时间: 2022-09-13 11:01:46

c语言 1到1000随机排列

声明一个数组,然后用循环将1000个数字顺序写入,再打乱数组元素
原来有人先回答了。。那我加上打乱1000个数组的函数吧 我用c++来着 不过貌似和c差不多

void xipai(int a[],int b)
{
for(int i=0,j,k;i<b;i++)
{
Sleep(10);
srand(clock());
j=rand()%1000;
k=a[i];
a[i]=a[j];
a[j]=k;
}
}

这是我上次写的洗牌算法。。。。。 你可以套用 改几个地方就行

❷ 用C++编写一个洗牌发牌的函数,玩家可能有两个、三个和四个

几乎所有的程序员都写过类似于“洗牌”的算法,也就是将一个数组随机打乱后输出,虽然很简单,但是深入研究起来,这个小小的算法也是大有讲究。我在面试程序员的时候,就会经常让他们当场写一个洗牌的函数,从中可以观察到他们对于这个问题的理解和写程序的基本功。

在深入讨论之前,必须先定义出一个基本概念:究竟洗牌算法的本质是什么?也就是说,什么样的洗牌结果是“正确”的?

云风曾经有一篇博文,专门讨论了这个问题,他也给出了一个比较确切的定义,在经过洗牌函数后,如果能够保证每一个数据出现在所有位置的概率是相等的,那么这种算法是符合要求的。在这个前提下,尽量降低时间复杂度和空间复杂度就能得到好的算法。

第一个洗牌算法:

随机抽出一张牌,检查这张牌是否被抽取过,如果已经被抽取过,则重新抽取,直到找到没被抽出过的牌,然后把这张牌放入洗好的队列中,重复该过程,直到所有的牌被抽出。

大概是比较符合大脑对于洗牌的直观思维,这个算法经常出现在我遇到的面试结果中,虽然它符合我们对于洗牌算法的基本要求,但这个算法并不好,首先它的复杂度为O(N2),而且需要额外的内存空间保存已经被抽出的牌的索引。所以当数据量比较大时,会极大降低效率。

第二个算法:

设牌的张数为n,首先准备n个不容易碰撞的随机数,然后进行排序,通过排序可以得到一个打乱次序的序列,按照这个序列将牌打乱。

这也是一个符合要求的算法,但是同样需要额外的存储空间,在复杂度上也会取决于所采用的排序算法,所以仍然不是一个好的算法。

第三个算法:

每次随机抽出两张牌交换,重复交换一定次数次后结束

void shuffle(int* data, int length)

{

for(int i=0; i<SWAP_COUNTS; i++)

{

//Rand(min, max)返回[min, max)区间内的随机数

int index1 = Rand(0, length);

int index2 = Rand(0, length);

std::swap(data[index1], data[index2]);

}

}

这又是一个常见的洗牌方法,比较有意思的问题是其中的“交换次数”,我们该如何确定一个合适的交换次数?简单的计算,交换m次后,具体某张牌始终没有被抽到的概率为((n-2)/n)^m,如果我们要求这个概率小于1/1000,那么 m>-3*ln(10)/ln(1-2/n),对于52张牌,这个数大约是176次,需要注意的是,这是满足“具体某张牌”始终没有被抽到的概率,如果需要满足“任意一张牌”没被抽到的概率小于1/1000,需要的次数还要大一些,但这个概率计算起来比较复杂,有兴趣的朋友可以试一下。

Update: 这个概率是,推算过程可以参考这里,根据这个概率,需要交换280次才能符合要求

第四个算法:

从第一张牌开始,将每张牌和随机的一张牌进行交换

void shuffle(int* data, int length)

{

for(int i=0; i<length; i++)

{

int index = Rand(0, length);

std::swap(data[i], data[index]);

}

}

很明显,这个算法是符合我们先前的要求的,时间复杂度为O(N),而且也不需要额外的临时空间,似乎我们找到了最优的算法,然而事实并非如此,看下一个算法。

第五个算法:

void shuffle(int* data, int length)

{

for(int i=1; i<length; i++)

{

int index = Rand(0, i);

std::swap(data[i], data[index]);

}

}

一个有意思的情况出现了,这个算法和第三种算法非常相似,从直觉来说,似乎使数据“杂乱”的能力还要弱于第三种,但事实上,这种算法要强于第三种。要想严格的证明这一点并不容易,需要一些数学功底,有兴趣的朋友可以参照一下这篇论文,或者matrix67大牛的博文,也可以这样简单理解一下,对于n张牌的数据,实际排列的可能情况为n! 种,但第四种算法能够产生n^n种排列,远远大于实际的排列情况,而且n^n不能被n!整除,所以经过算法四所定义的牌与牌之间的交换程序,很可能一张牌被换来换去又被换回到原来的位置,所以这个算法不是最优的。而算法五输出的可能组合恰好是n!种,所以这个算法才是完美的。

事情并没有结束,如果真的要找一个最优的算法,还是请出最终的冠军吧!

第六个算法:

void shuffle(int* data, int length)

{

std::random_shuffle(data, data+length);

}

没错,用c++的标准库函数才是最优方案,事实上,std::random_shuffle在实现上也是采取了第四种方法,看来还是那句话,“不要重复制造轮子”

不想写 - -

❸ C语言 洗牌算法

/*洗牌程序:用任何语言,随机分配52张扑克牌到52个位置上,每个位置只容许放一张牌
用1-13表示红心A--K
14-26表示黑桃A,2,3-,Q,K
27-39表示方块A,2,3-,Q,K
40-52表示黑桃A,2,3-,Q,K
也就是生成1-52不重复的随机数,放到数组中*/

#include<iomanip.h>
#include<stdlib.h>
#include<time.h>

const int N=52;
static int a[N];

int create(int n)
{
return (1+rand()%52);
}

int main()
{
int i,j;
srand(time(0));
for(i=0;i<N;++i)
{
a[i]=create(N);
for(j=0;j<i;++j)
{
if(a[j]==a[i])
{
a[i]=(a[i]+1)%52;
}
}
cout<<setw(5)<<a[i];
}
cout<<endl;
return 0;
}

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

我找了此资料,一起共享


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

假如你有一个布袋或者抽屉,里面有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个元素返回。

SubGetRnd(arr,n)
Randomize
Fori=1Ton'正序洗牌1ton简化代码
r=Int(Rnd()*(n-i+1))+i
t=arr(r):arr(r)=arr(i):arr(i)=t'下标1开始一维代码
Next
EndSub

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

SubGetRnd(arr,n)

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

Fori=1Ton'遍历1ton

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'循环抽取、置换、存贮抽取结果

EndSub

❺ 急求 用C程序表示一副扑克牌

对我的回答有什么疑问或要求,可以Hi我。
//一副牌升级,模拟发牌程序,供参考:
//第五家的牌即为底牌
//大小王的ASCII我的VC中显示不出来,所以用“大”“小”代替
//算法:用随机数模拟洗牌。产生两个1~54之间的随机数,然后交换对应的两张牌。
//洗牌模块非原创
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
int i,temp,r;
int pk[54]={501,502,
101,102,103,104,105,106,107,108,109,110,111,112,113,
201,202,203,204,205,206,207,208,209,210,211,212,213,
301,302,303,304,305,306,307,308,309,310,311,312,313,
401,402,403,404,405,406,407,408,409,410,411,412,413};
printf("\n");
srand((unsigned int)time(NULL));
for(i=0;i<53;i++) //洗牌
{
r=rand()%(53-i)+i+1;//加1为了洗最后一张牌
temp=pk[i];
pk[i]=pk[r];
pk[r]=temp;
}
int k=1;
for(i=0;i<54;i++)//输出每家的牌
{
if(i%12==0)printf("\n第%d家的牌:",k++);
switch(pk[i]/100)
{
case 1:printf(" \003");break;//黑桃
case 2:printf(" \006");break;//红桃
case 3:printf(" \005");break;//梅花
case 4:printf(" \004");break;//方块
case 5:
switch(pk[i]%100)
{
case 1:printf(" 大 ");break;//大王
case 2:printf(" 小 ");break;//小王
}
}
switch(pk[i]%100)
{
case 1:if(pk[i]/100!=5)printf("%-2c",'A');break;
case 2:if(pk[i]/100!=5)printf("%-2d",pk[i]%100);break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:printf("%-2d",pk[i]%100);break;
case 11:printf("%-2c",'J');break;
case 12:printf("%-2c",'Q');break;
case 13:printf("%-2c",'K');break;
}
}
printf("\n");
return 0;
}

❻ 兄弟能帮忙解决个c语言问题自动发牌 帮我看下我的程序具体怎么才能实现按先分花色,每种花色再按大小排

你的算法搞得太复杂了!给puke按花色和大小加上一个编号从0~51,每张牌对应一个编号。在程序里直接对编号操作(发牌、洗牌、排序等)就容易多了。

❼ C语言问题.急!

还原需要16次,不是20次,源码和输出结果如下:
/****************************
模拟洗牌-完美洗牌法
****************************/
voidmain()
{
inti,j;
inta[52],b[52];
charpoker[52][4]={
"AH","2H","3H","4H","5H","6H","7H","8H","9H","10H","JH","QH","KH",
"AC","2C","3C","4C","5C","6C","7C","8C","9C","10C","JC","QC","KC",
"AD","2D","3D","4D","5D","6D","7D","8D","9D","10D","JD","QD","KD",
"AS","2S","3S","4S","5S","6S","7S","8S","9S","10S","JS","QS","KS"};

for(i=0;i<52;i++)a[i]=i;
for(j=0;j<52;j++)
{
printf("%s",poker[a[j]]);
if(j%13==12)printf("\n");
}
printf("----\n");

for(i=0;i<16;i++)
{
for(j=0;j<26;j++)
{
b[2*j]=a[j];
}
for(j=26;j<52;j++)
{
b[2*(j-26)+1]=a[j];
}
for(j=0;j<52;j++)
{
printf("%s",poker[b[j]]);
if(j%13==12)printf("\n");
}
printf("----\n");

for(j=0;j<52;j++)a[j]=b[j];
}
getch();
}

输出结果:
AH2H3H4H5H6H7H8H9H10HJHQHKH
AC2C3C4C5C6C7C8C9C10CJCQCKC
AD2D3D4D5D6D7D8D9D10DJDQDKD
AS2S3S4S5S6S7S8S9S10SJSQSKS
----
AHAD2H2D3H3D4H4D5H5D6H6D7H
7D8H8D9H9D10H10DJHJDQHQDKHKD
ACAS2C2S3C3S4C4S5C5S6C6S7C
7S8C8S9C9S10C10SJCJSQCQSKCKS
----
AHACADAS2H2C2D2S3H3C3D3S4H
4C4D4S5H5C5D5S6H6C6D6S7H7C
7D7S8H8C8D8S9H9C9D9S10H10C10D
10SJHJCJDJSQHQCQDQSKHKCKDKS
----
AH7DAC7SAD8HAS8C2H8D2C8S2D
9H2S9C3H9D3C9S3D10H3S10C4H10D
4C10S4DJH4SJC5HJD5CJS5DQH5S
QC6HQD6CQS6DKH6SKC7HKD7CKS
----
AH4C7D10SAC4D7SJHAD4S8HJCAS
5H8CJD2H5C8DJS2C5D8SQH2D5S
9HQC2S6H9CQD3H6C9DQS3C6D9S
KH3D6S10HKC3S7H10CKD4H7C10DKS
----
AH9H4CQC7D2S10S6HAC9C4DQD7S
3HJH6CAD9D4SQS8H3CJC6DAS9S
5HKH8C3DJD6S2H10H5CKC8D3SJS
7H2C10C5DKD8S4HQH7C2D10D5SKS
----
AH5H9HKH4C8CQC3D7DJD2S6S10S
2H6H10HAC5C9CKC4D8DQD3S7SJS
3H7HJH2C6C10CAD5D9DKD4S8SQS
4H8HQH3C7CJC2D6D10DAS5S9SKS
----
AH3H5H7H9HJHKH2C4C6C8C10CQC
AD3D5D7D9DJDKD2S4S6S8S10SQS
2H4H6H8H10HQHAC3C5C7C9CJCKC
2D4D6D8D10DQDAS3S5S7S9SJSKS
----
AH2H3H4H5H6H7H8H9H10HJHQHKH
AC2C3C4C5C6C7C8C9C10CJCQCKC
AD2D3D4D5D6D7D8D9D10DJDQDKD
AS2S3S4S5S6S7S8S9S10SJSQSKS
----
AHAD2H2D3H3D4H4D5H5D6H6D7H
7D8H8D9H9D10H10DJHJDQHQDKHKD
ACAS2C2S3C3S4C4S5C5S6C6S7C
7S8C8S9C9S10C10SJCJSQCQSKCKS
----
AHACADAS2H2C2D2S3H3C3D3S4H
4C4D4S5H5C5D5S6H6C6D6S7H7C
7D7S8H8C8D8S9H9C9D9S10H10C10D
10SJHJCJDJSQHQCQDQSKHKCKDKS
----
AH7DAC7SAD8HAS8C2H8D2C8S2D
9H2S9C3H9D3C9S3D10H3S10C4H10D
4C10S4DJH4SJC5HJD5CJS5DQH5S
QC6HQD6CQS6DKH6SKC7HKD7CKS
----
AH4C7D10SAC4D7SJHAD4S8HJCAS
5H8CJD2H5C8DJS2C5D8SQH2D5S
9HQC2S6H9CQD3H6C9DQS3C6D9S
KH3D6S10HKC3S7H10CKD4H7C10DKS
----
AH9H4CQC7D2S10S6HAC9C4DQD7S
3HJH6CAD9D4SQS8H3CJC6DAS9S
5HKH8C3DJD6S2H10H5CKC8D3SJS
7H2C10C5DKD8S4HQH7C2D10D5SKS
----
AH5H9HKH4C8CQC3D7DJD2S6S10S
2H6H10HAC5C9CKC4D8DQD3S7SJS
3H7HJH2C6C10CAD5D9DKD4S8SQS
4H8HQH3C7CJC2D6D10DAS5S9SKS
----
AH3H5H7H9HJHKH2C4C6C8C10CQC
AD3D5D7D9DJDKD2S4S6S8S10SQS
2H4H6H8H10HQHAC3C5C7C9CJCKC
2D4D6D8D10DQDAS3S5S7S9SJSKS
----
AH2H3H4H5H6H7H8H9H10HJHQHKH
AC2C3C4C5C6C7C8C9C10CJCQCKC
AD2D3D4D5D6D7D8D9D10DJDQDKD
AS2S3S4S5S6S7S8S9S10SJSQSKS
----

❽ C语言 洗牌

下面是正确的代码,没有用链表,通过4个数组来做的,必要的注释我都加了。不理解可以问我。

cout相当于printf,cin相当于scanf。

#include "iostream"

using namespace std;

int main()
{
int num;
cout << "请输入特定数n:";
cin >> num;

int *arry = new int[2*num];
int *temp = new int[2*num];
int *t1 = new int[num];
int *t2 = new int[num];
//初始化数组
for(int j=0;j<2*num;j++)
{
arry[j] = temp[j] = j;
}

//以下是循环部分
bool gogo = true;
int count = 0;

while(gogo)
{
//更新奇、偶数组
for(int i=0; i<2*num; i++)
{
if(i<num)
t1[i] = temp[i];
else
t2[(i-num)] = temp[i];
}

//重组temp数组
for(i=0; i<2*num; i++)
{
if(i%2==0)
temp[i] = t2[i/2] ;
else
temp[i] = t1[(i-1)/2];
}

//判断重组后的数组temp是否和原来的数组一样
for(i=0; i<2*num; i++)
{
if(arry[i] != temp[i])
{
break;
}
}
//如果完全相同,则此时 i==2n;
if(i==2*num)
gogo = false;

count++;
}

cout << count << "次后数组恢复到原来的次序。";

return 0;
}

❾ Objective-C 语言实现 Knuth 洗牌算法

没做过这个,但是你可以找c语言的代码来用,完全支持

❿ 如何用C语言产生不重复的0到9之间的随机数

刚调试了下,弄不明白的是,为什么SZ[10]明明不存在却永远是产生的r对应输出的数。。。

。。。。又研究了20分钟,终于弄懂了。。。实际上应该是9更标准一些,虽然10不会溢出。。。rang()%(10-i)第一个从0-9里选,然后选过的消失。。。最后一个为9

第二次从0-8里选,选过的消失。。。最后2个为9,以后永远都选不上第8和第九。无论9出没出现过,以此类推。最终全部为九,其余消失。

如果为10的话,其实也影响不了,因为最后几个数永远都不会取到、

采纳了吧。。。。。。

额,其实最标准的应该把那个地方改成9-i,把没选的数字往前推,但是已经出现的过的就不必推了。。。

热点内容
服务器地址和端口如何区分 发布:2025-05-16 01:03:17 浏览:832
重新编目数据库 发布:2025-05-16 00:54:34 浏览:513
android语音控制 发布:2025-05-16 00:53:50 浏览:265
win8windows无法访问 发布:2025-05-16 00:37:53 浏览:894
八种排序算法 发布:2025-05-16 00:37:17 浏览:55
左旋螺纹数控编程实例 发布:2025-05-16 00:11:49 浏览:10
安卓游戏旧版本从哪个软件下载 发布:2025-05-16 00:00:20 浏览:329
连接聚类算法 发布:2025-05-15 23:55:09 浏览:978
工资算法单休 发布:2025-05-15 23:52:30 浏览:819
超凡先锋配置不行怎么办 发布:2025-05-15 23:27:54 浏览:532