洗牌算法分析总结

Fisher-Yates洗牌算法分析与理解 问题 打乱一个没有重复元素的数组 常规暴力解法 讲数组的所有元素复制一份保存在一个ArrayList内,遍历数组,每次遍历生成一个在0到链表大小之间的随机数,将对应索引处的数组元素替换成链表中该随机数对应索引处的元素值,并从链表中移除该元素。 时间复杂度: O(n*n) 空间复杂度: O(n) Fisher-Yates洗牌算法 思路 我们可以用一个简单的技巧来降低之前算法的时间复杂度和空间复杂度,那就是让数组中的元素互相交换,这样就可以避免掉每次迭代中用于修改列表的时间了。 算法 阅读详情
先定义出一个基本概念:究竟洗牌算法的本质是什么?也就是说,什么样的洗牌结果是“正确”的?一个比较确切的定义,在经过洗牌函数后,如果能够保证每一个数据出现在所有位置的概率是相等的,那么这种算法是符合要求的。在这个前提下,尽量降低时间复杂度和空间复杂度就能得到好的算法。


第一个算法


随机抽出一张牌,检查这张牌是否被抽取过,如果已经被抽取过,则重新抽取,直到找到没被抽出过的牌,然后把这张牌放入洗好的队列中,重复该过程,直到所有的牌被抽出。它符合我们对于洗牌算法的基本要求,但它的复杂度为O(N^2),而且需要额外的内存空间保存已经被抽出的牌的索引。所以当数据量比较大时,会极大降低效率。


第二个算法


设牌的张数为n,首先准备n个不容易碰撞的随机数,然后进行排序,通过排序可以得到一个打乱次序的序列,按照这个序列将牌打乱。这也是一个符合要求的算法,但是同样需要额外的存储空间,在复杂度上也会取决于所采用的排序算法。


第三个算法


每次随机抽出两张牌交换,重复交换一定次数次后结束。这是一个常见的洗牌方法,比较有意思的问题是其中的“交换次数”,我们该如何确定一个合适的交换次数?简单的计算,交换m次后,具体某张牌始终没有被抽到的概率为((n-2)/n)^m,如果我们要求这个概率小于1/1000,那么 m>-3*ln(10)/ln(1-2/n),对于52张牌,这个数大约是176次,需要注意的是,这是满足“具体某张牌”始终没有被抽到的概率,如果需要满足“任意一张牌”没被抽到的概率小于1/1000,需要的次数还要大一些,需要交换280次才能符合要求。
void shuffle_3(int data[], int length)
{
#define COUNT 54
     int i = 0, idx1 = 0, idx2 = 0;
     for(i = 0; i < COUNT; i++)
     {
          idx1 = fix_random(0, length - 1);
          idx2 = fix_random(0, length - 1);
          swap(&data[idx1], &data[idx2]);
     }
     return;
}


 

第四个算法


从第一张牌开始,将每张牌和随机的一张牌进行交换。很明显,这个算法是符合我们先前的要求的,时间复杂度为O(N),而且也不需要额外的临时空间,似乎我们找到了最优的算法,然而事实并非如此。
void shuffle_4(int data[], int length)
{
     int i = 0, idx = 0;
     for(i = 0; i < length; i++)
     {
          idx = fix_random(0, length - 1);
          swap(&data[idx], &data[i]);
     }
     return;
}


 

第五个算法

 
从第一张牌开始,将每张牌和这张牌之前的随机的一张牌进行交换。
void shuffle_5(int data[], int length)
{
     int i = 0, idx = 0;
     for(i = 0; i < length; i++)
     {
          idx = fix_random(0, i);
          swap(&data[idx], &data[i]);
     }
     return;
}


 

总结

 

实际排列的可能情况有N!种;算法四的输出有N*N中,算法五的输出有N!种,而且N*N不能被N!整除,所以经过算法四所定义的牌与牌之间的交换程序,很可能一张牌被换来换去又被换回到原来的位置,所以这个算法不是最优的。而算法五输出的可能组合恰好是n!种,所以这个算法才是完美的。

 

洗牌程序

 

将54张扑克牌按顺序编号,0和53为大王和小王,1~12为黑色,13~24为红色,25~36为花色,37~52为方片

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

inline void swap(int *a, int *b)
{
     int tmp = 0;
     tmp = *a;
     *a = *b;
     *b = tmp;
}

inline int fix_random(int start, int end)
{
     return start + rand()%(end -start + 1);
}


void init_card(int data[], int length)
{
     int i = 0;
     for(i = 0; i < length; i++)
     {
          data[i] = i;
     }
     return;
}

void out_card(int data[], int length)
{
#define NUMPERLINE 6
     int i = 0;
     for(i = 0; i < length; i++)
     {
          printf("%d\t",data[i]);
          if( (i+1) % NUMPERLINE == 0)
          {
               printf("\n");    
          }
     }
     printf("\n");
     return;
}

#define CARD_NUM 54
int main()
{
     int *data = (int *)malloc(CARD_NUM * sizeof(int));
     if(NULL == data)
     {
          printf("Failed to alloc memory for card.\n");
          return 0;
     }
     memset(data, 0x0, CARD_NUM * sizeof(int));
     init_card(data, CARD_NUM);
     printf("Out card:\n");
     out_card(data, CARD_NUM);

     shuffle_4(data, CARD_NUM);
     printf("Shuffle, out card:\n");
     out_card(data, CARD_NUM);

     shuffle_5(data, CARD_NUM);
     printf("Shuffle, out card:\n");
     out_card(data, CARD_NUM);

     shuffle_3(data, CARD_NUM);
     printf("Shuffle, out card:\n");
     out_card(data, CARD_NUM);
    
     free(data);
}


 

麻将游戏洗牌算法分析与跨平台 C/C++ 实现 在麻将游戏中,洗牌算法是一个重要的步骤,用于将牌堆中的牌打乱,以确保游戏的公平性和随机性。本文将分析麻将游戏的洗牌算法,并提供一个跨平台的 C/C++ 实现。总结起来,本文介绍了麻将游戏的洗牌算法,并提供了一个跨平台的 C/C++ 实现示例。洗牌算法的基本思想是通过随机交换牌堆中的牌来打乱它们的顺序。常用的洗牌算法有 Fisher-Yates 算法,也称为 Knuth 洗牌算法。这段代码可以在 C++ 的各种平台上运行,并且通过生成随机数来保证洗牌的随机性。麻将游戏洗牌算法分析与跨平台 C/C++ 实现。 阅读详情

相关推荐

麻将游戏C++洗牌算法分析并实现跨平台

linux需要包含string头文件 #include 可正常运行。至此,该洗牌方法已实现了跨平台。麻将数组声明定义也要改。xcode运行也OK。

1258

洗牌算法

目录 一、什么是洗牌算法 二、如何去打乱 三、例题 一、什么是洗牌算法 现在有一副扑克牌,让你去洗牌,怎么洗牌才能让每一种牌之间的组合出现的概率相等? 简单的问题往往隐藏了重要信息,比如这里我们可以将洗牌理解为将这副牌打乱,那么什么才叫乱呢? 其中有两个要素: 随机的结果要能够覆盖所有的情况,(譬如 n张牌,最后的结果有 n! 情况,结果所有顺序必须都能够出现)。 所有出现的结果 概率 相等。 二、如何去打乱 首先,设定我们已经拥有了系统提供的rand函数,能够提供一个给定范围内的随机数

ThinPikachu的博客 4160

洗牌算法(感觉有点用)

通过产生随机数进行交换,次数越多,越接近随机

洗牌算法(Shuffle Algorithm)Fisher-Yates 洗牌算法详细解读

洗牌算法(Shuffle Algorithm)用于将一组元素随机打乱,类似于洗牌过程中将牌随机排列的过程。Fisher-Yates 洗牌算法是最经典且高效的洗牌算法,能够确保生成的排列是等概率的(即每一种排列出现的概率相同),其时间复杂度为 O(n)。

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 6354

洗牌算法思路讲解(程序员面试题)

洗牌算法是我在面试过程中遇到的一个问题,我事后做了整理,与大家分享下思路,这个文档是我自己写的,如要转载,请注明出处。联系方式在文档里有说明。有什么想法或思路希望与我一起交流。

基于折叠技术的大数据样本洗牌算法研究.pdf

基于折叠技术的大数据样本洗牌算法研究.pdf

一文详解:菠菜公司棋牌游戏中的洗牌和发牌算法

前言 关于棋牌类游戏中的洗牌和发牌算法**关键词:**棋牌游戏,洗牌算法,发牌算法,算法,JS,麻将 洗牌和发牌是棋牌类游戏中,非常重要的两个关键节点,而这两个关键节点涉及的算法,很多同学非常感兴趣,今天,我们就以NodeJS环境为例,通过JS代码给大家解说洗牌和发牌算法。 一、洗牌算法 1. 采用随机交换策略 【方法一】核心思想:随机产生一个位置与当前位置的牌交换。 运行结果如下: 【方法二】核心思想:随机产生一个位置与第一张牌进行交换,交换的轮次越多,理论上次序越乱。 运行结果如下: 2. 采用

voidinit的专栏 1万+

DeepSeek绝了!3分钟生成PPT,专治“五彩斑斓的黑“!!(保姆教程)

DeepSeek绝了!3分钟生成PPT,专治"五彩斑斓的黑"!!(保姆教程)

yizhen91y的博客 4万+

洗牌算法简单分析

关于洗牌算法,网上有比较多的实现,一个比较简单直接的实现如下: void ShuffleArray_Fisher_Yates(char* arr, int len) { int i = len, j; char temp; if ( i == 0 ) return; while ( --i ) { j = rand() % (i+1);

飞鸟 1148

MATLAB2022b安装

图文并茂,手把手教会你怎么安装MATLAB2022b

1万+

基于YOLOv8和PaddlepaddleOCR的微信截图聊天记录提取

本文提出了一种基于YOLOv8和PaddleOCR的微信聊天记录提取方法。首先使用YOLOv8n模型分割出聊天气泡(针对深浅色模式分别训练),通过合成数据集增强模型鲁棒性,召回率达0.995。随后采用PP-OCRv5进行文本识别,利用坐标匹配将气泡内文本送入识别队列,短长文本平均置信度分别>0.98和>0.95。文中特别强调了PaddleOCR不同版本的输出格式差异及适配方案,建议使用3.0+版本。该方法有效解决了直接OCR识别易受干扰的问题,通过气泡分割+文本定位的两阶段策略显著提升了识别准确

2401_87383958的博客 2353

数组中随机抽取_【算法】扑克随机洗牌算法分析

一、算法说明洗牌算法实际上就是常见的随机问题。我们可以抽象理解为:得到一个M以内的所有自然数的随机顺序数组。然而怎么样操作才是好的洗牌算法呢?我们通常认为得保证概率相等。即洗牌之后,如果能够保证每一个数出现在所有位置上的概率是相等的。二、算法实现算法1:随机抽取单张牌① 随机抽出一张牌② 检查这种牌是否被抽取过,如果已经被抽取过,则重新抽取,直到找到没有被抽取的牌;③ 重复上述过程,直到所有的牌都...

weixin_29690065的博客 701

Zabbix Trigger actions访问出现500

本篇博客详细介绍了Zabbix访问'Trigger actions'出现的错误状况,访问界面出现500,并提供了解决方案。

格子的博客 562

java快速实现洗牌算法_javascript随机之洗牌算法深入分析

洗牌算法是我们常见的随机问题,在玩游戏、随机排序时经常会碰到。它可以抽象成这样:得到一个M以内的所有自然数的随机顺序数组。在百度搜“洗牌算法”,第一个结果是《百度文库-洗牌算法》,扫了一下里面的内容,很多内容都容易误导别人走上歧途,包括最后用链表代替数组,也只是一个有限的优化(链表也引入了读取效率的损失)。该文里的第一种方法,可以简单描述成:随机抽牌,放在另一组;再次抽取,抽到空牌则重复抽。“抽到...

weixin_39826342的博客 374

[QMT量化交易小白入门]-十二、QMT回测龙头打首板和连板的策略

class a():passA = a() #创建空的类的实例 用来保存委托状态field_list定义了需要的市场数据字段,而类a用于保存交易状态。

木头大左的博客 4757

军品研制过程评审活动-(一)论证阶段

军品研制过程评审活动-(一)论证阶段

Abel的博客 3814

洗牌算法分析

洗牌算法分析

cpyname的博客 602

微信小程序 - 真机调试调用接口报错{errno: 600001, errMsg: “request:fail -102:net::ERR_CONNECTION_REFUSED},真机运行测试请求异常

微信小程序,真机,调试测试,运行报错,API接口,服务器接口都报错了,小程序报错errno: 600001,小程序报错request:fail -102:net::ERR_CONNECTION_REFUSED,真实手机打开接口全都失效了,微信小程序真机测试失败,微信小程序{errno: 600001, errMsg: "request:fail -102:net::ERR_CONNECTION_REFUSED"},详细解决方法,https,服务器SSL证书,无法解决,服务器更换SSL证书,接口地址改了也不行

🏆 前端领域优质创作者 1万+

几种随机洗牌算法的分析比较

卡牌游戏中常常需要洗牌,今天正好看到了这样的题目,搜索了些许资料,整理并且理解后,决定写出来,算法的名字无从考证,全是自己理解后给的名字,如果您有哪个算法的信息或者错误之处可以随时联系我,还请多多关照。

我从废墟中走来 4053

使用SSC添加大量的SDO条目

使用SSC添加大量的SDO条目 SSC用表格添加SDO,PDO部分必须指定到0x1600和0x1A00分配TxPdo和RxPdo映射,在0x1C12和0x1C13分别分配到SM2和SM3。在0x6000和0x7000未指定的entry就是SDO部分。

PI_sunyang的博客 3165

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

编程常用算法分析——洗牌算法

首先我们需要明白几个数学思想—————————————— 一、 我们的洗牌算法是伪随机事件的一种。而随机事件我们也要明白几个概念   随机数的特性: 随机性:不存在统计学偏差,是完全杂乱的数列 不可预测性:不能从过去的数列推测出下一个出现的数 不可重现性:除非将数列本身保存下来,否则不能重现相同的数列   随机数分为真随机数和伪随机数,我们程序使用的基本都是伪随机数,其中伪随机又分为...

weixin_41686779的博客 788

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

shuffle洗牌算法java_Collections.shuffle()源码分析

Collections.shuffle()源码分析源代码展示:public class Collections {private static Random r;private static final int SHUFFLE_THRESHOLD = 5;public static void shuffle(List> list) {if (r == null) {r =...

weixin_31539461的博客 314

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

数据分析|Fisher-Yates 洗牌算法(原地)

洗牌算法

长行 471
上一篇: C语言实现全排列
下一篇: 来自腾讯无线研发的经验分享
IT_Linux
博客等级 码龄14年 31粉丝 77原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值