游戏常用算法-洗牌算法

游戏常用算法-洗牌算法洗牌算法是一个比较常见的面试题。一副扑克54张牌,有54!种排列方式。最佳的洗牌算法,应该能够等概率地生成这54!种结果中的一种

大家好,又见面了,我是你们的朋友全栈君。

洗牌算法是一个比较常见的面试题。

一副扑克54张牌,有54!种排列方式。最佳的洗牌算法,应该能够等概率地生成这54!种结果中的一种

基于Unity的洗牌算法代码实现

GitHub链接

<span role="heading" aria-level="2">游戏常用算法-洗牌算法

抽牌洗牌

原理

这是完全合乎现实洗牌逻辑的算法。

就是抽出纸牌的最后一张随机插入到牌库中,这般抽54次就完成了对扑克牌的洗牌

复杂度

空间O(1),时间O(n^2)

优缺点

如果牌库是以一个数组描述,这种插入式的洗牌不可避免地要大量移动元素。

Fisher_Yates算法

原理

取两个列表,一个是洗牌前的序列A{1,2….54),一个用来放洗牌后的序列B,B初始为空

while A不为空

随机从A取一张牌加入B末尾

复杂度

空间O(n),时间O(n^2)

代码实现

 1 List<int> list = new List<int>(pukes.pukes);//洗牌前的序列A
 2 List<int> newlist = new List<int>(list.Count);//洗牌后的序列B
 3 for(int i = 0 ; i < pukes.pukes.Length ; ++i)
 4 {
 5   int randomIndex = Random.Range(0, list.Count);
 6   int r = list[randomIndex];//随机取牌
 7    newlist.Add(r);
 8    list.RemoveAt(randomIndex);
 9 }
10 pukes.ResetPuke(newlist.ToArray());//序列B为洗牌后的结果

优缺点

算法原理清晰,但额外开辟了一个List,而且为List删除元素是不可避免地需要移动元素

通过54次生成的随机数取1/54,1/53,…1/1能等概率地生成这54!种结果中的一种

Knuth_Durstenfeld算法

Knuth 和Durstenfeld 在Fisher 等人的基础上对算法进行了改进。 每次从未处理的数据中随机取出一个数字,然后把该数字放在数组的尾部, 即数组尾部存放的是已经处理过的数字 。 这是一个原地打乱顺序的算法,算法时间复杂度也从Fisher算法的 O ( n 2 )提升到了 O ( n )。

 

1 for(int i = pukes.pukes.Length - 1;i>0;--i)
2   {
3       int randomIndex = Random.Range(0, i+1);
4       pukes.Swap(randomIndex, i);
5   }

是最佳的洗牌算法

Inside_Out算法

C++ stl中random_shuffle使用的就是这种算法

原理

在[0, i]之间随机一个下标j,然后用位置j的元素替换掉位置i的数字

通过54次生成的随机数取1/1,1/2,…1/54能等概率地生成这54!种结果中的一种

复杂度

空间O(1),时间O(n)

代码实现

1 public static void Shuffle(Pukes pukes)
2   {
3       int len = pukes.pukes.Length;
4       for (int i = 0; i < len; ++i)
5       {
6           int randomIndex = Random.Range(0, i + 1);
7           pukes.Swap(i, randomIndex);
8       }
9   }

random_shuffle

关于c++ stl 的random_shuffle

它的算法原理和Knuth_Durstenfeld类似

先从所有元素中选一个与位置1的元素交换,然后再从剩下的n-1个元素中选择一个放到位置2,以此类推

参考链接

维基百科-Fisher–Yates shuffle

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/155556.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • SpringBoot — 软件许可(License)证书生成+验证+应用完整流程

    SpringBoot — 软件许可(License)证书生成+验证+应用完整流程一、项目目录树结构由于时间有限,不可能在博客上花太多时间、也不可能每一个细节都说的很细,所以,下面的内容虽然一时间看着比较懵,但是文末有项目的GitHub地址,或者不懂的可以留言;这个是粗糙的项目结构,没有细分,实际应用的话应该是授权的代码要和验证的代码分开,防止授权的代码引进客户端系统中,被激活成功教程和拆穿,也为了防止公钥st…

  • 近期技术讨论贴(持续更新:12-10)

    近期技术讨论贴(持续更新:12-10)http://bbs.blueidea.com/thread-2455309-1-1.html转载于:https://www.cnblogs.com/jikey/archive/2009/12/24/1631436.html

  • quotename()函数 

    quotename()函数 请教quotename函数的理解,我已经看了很多帮助,储如以下示例 QUOTENAME(Transact-SQL)返回带有分隔符的Unicode字符串,分隔符的加入可使输入的字符串成为有效的MicrosoftSQLServer2005分隔标识符。Transact-SQL语法约定语法QUOTENAME(‘character_string'[,’q…

  • java不求有功,但求无过—异常处理

    java不求有功,但求无过—异常处理

    2021年11月29日
  • javascript_JavaScript走向成熟

    javascript_JavaScript走向成熟javascript明年JavaScript将有20年的历史(从首次在Netscape浏览器中首次亮相开始算起)。这是一门具有悠久历史的语言,并且从其早期开始就带来了很多负担,但是随着它离开少年时代的到来,我认为这是一种最终发展起来的语言。JavaScript通过允许脚本在浏览器中运行来彻底改变了Web。但是,在最初流行之后,它很快就开始受到不良声誉,并且经常与编写不良,剪切粘贴的代码…

  • verilog流水线设计代码_十进制BCD译码器的verilog

    verilog流水线设计代码_十进制BCD译码器的verilog流水线概述如下图为工厂流水线,工厂流水线就是将一个工作(比如生产一个产品)分成多个细分工作,在生产流水线上由多个不同的人分步完成。这个待完成的产品在流水线上一级一级往下传递。比如完成一个产品,需要8道工序,每道工序需要10s,那么流水线启动后,不间断工作的话,第一个产品虽然要80s才完成,但是接下来每10s就能产出一个产品。使得速度大大提高。当然这也增加了人员等资源的付出。对于电路的流水线…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号