Python不用学,看看你就懂;拿来就能用,用用你就会

无需安装编程软件,把代码拷贝到在线编辑器即可运行

考虑一下扑克牌,如何用电脑编程做到高效而完美地洗牌呢?

要求是代码少、效率高,洗牌的结果要同时满足以下三个条件才算“完美”:初始状态无关性:洗牌后每张牌的位置与此前它的位置无关;

随机出现独立性:每张牌将出现的位置与其它牌是什么位置无关;

概率均衡相等性:每张牌在每个位置出现的概率完全一样,为1/N,N为牌的总张数。

你可以看到,那些“完美”的扑克牌手工洗牌——对半分然后一张一张交替插入的手法,虽然潇洒,洗牌效果却是不完美的,因为它显然不符合第1条“初始状态无关性”,并且也很有可能不符合第2条“随机出现独立性”。

还有一个隐含条件:不能重复,因为扑克牌每种牌只有一张。

考虑到上述条件,计算机编程应该如何做?

一种想法是,简单地采用范围 [1,N] 的随机数产生洗牌序列,每次与已经产生的牌点比较,有重复则放弃掉并重新产生。这种方法在已经产生大部分牌后,新生成的随机数与前面重复的可能性很大,因此要生成很多个随机数才能确定一张新位置的牌点。这样就不科学了,效率实在太低。

第二种想法是,随机产生第一张牌,然后用一个简单的算法依次产生后面的牌,算法本身保证牌点不会重复。为便于理解,例如只有5张牌,算法是循环加一个随机数d=[1,4]。若随机产生第一张牌3,且d=2,那么序列就是35241。若随机产生第一张牌4,且d=3,序列就是42531。表明上看这是双重随机,挺厉害的,其实此法不符合第2个条件独立随机性。所以这种做法虽然效率可以做到很高,但效果做不到完美。

第三种想法是,把扑克牌的所有排列组合保存下来,然后随机取一个。54张牌一共有54!种排列,存好,然后在[1,54!]范围中产生一个随机数,给出该随机数对应的那个序列即可。此法从洗牌结果来说,当然是完美的,但效率非常非常非常低下,老破计算机怕是要死机。^_^

以上都不行,那有没有完美而高效的洗牌算法呢?

有,比如大名鼎鼎的Knuth洗牌算法。其核心代码只有一个for循环:

for(int i = N - 1; i >= 0 ; i -- )

swap(arr[i], arr[rand(0, i)]) // rand(0, i) 生成 [0, i] 之间的随机整数

这个算法非常巧妙,被誉为“神一样的算法”,然而解释它是要费点儿功夫的,还要搞些图片甚至动画什么的来帮助理解,例如:有哪些算法惊艳到了你?你若觉得理解这个算法有点儿费脑筋费时间,没关系,请先看看我下面给的算法。

我们也可以把洗牌看作是一个随机发完牌的过程:从原牌堆中一张一张随机取出牌,依次放到新牌堆中(每取出一张,原牌堆中就要删除这张),取完了,新牌堆就是一副洗好的牌。

这种方法直观而容易理解。它其实是Knuth洗牌算法的前身,叫Fisher-Yates洗牌算法

for i in range(N):

list2.append(random.choice(list1)) # 从原牌堆中随机抽取一张牌放到新牌堆中

list1.remove(list2[i]) # 从原牌堆中删除刚才抽到的那张牌

怎么样?很好理解吧。理解了这个算法,再点进去看刚才提到的帖子,你会发现Knuth算法相当于只是省掉了第二个数组的空间,把第一个数组空出来的位置给新牌堆用而已。所以这样一来,Knuth算法就变得很好理解了。

根据上述过程描述,该算法显然满足完美性的第1个条件和第2个条件,而要证明其满足第3个条件“等概率性”,也很简单:总牌数为N,则任意一张牌出现在第1个位置的几率为1/N,出现在第2个位置的几率为(1-1/N) x 1/(N-1) = 1/N(即第1个位置没出现而现在恰好出现的几率),余此类推,出现在任意第k个位置的几率也是1/N:

此算法的效率虽然比Knuth洗牌算法低一些,但也相当不错,实测在普通家用电脑上54张牌洗一万次,或者一万张牌洗一次,都是瞬间完成的事情。关键是,此算法无论其原理还是其Python编程的实现,都很好理解,所以我们把它作为高效而完美洗牌的Python编程范例。

下面是采用Python编程的完整代码及演算结果示例:

import random

TOTAL_NUMBER = 54 # 牌的总张数

DEAL_NUMBER = 54 # 发牌张数,等于牌的总张数时相当于洗牌

list1 = [i+1 for i in range(TOTAL_NUMBER)] # 初始化原牌堆,方法无所谓,完整而不重复即可

list2 = [] # 新牌堆开始时为空

for i in range(DEAL_NUMBER):

list2.append(random.choice(list1)) # 从原牌堆中随机抽取一张牌放到新牌堆中

list1.remove(list2[i]) # 从原牌堆中删除刚才抽到的那张牌

print("A new card list produced:\n",list2)

---------------------

A new card list produced:

[52, 54, 15, 47, 14, 36, 19, 43, 8, 12, 30, 34, 18, 27, 16, 39, 40, 24, 2, 50, 10, 51, 7, 21, 42, 6, 45, 31, 25, 28, 5, 4, 1, 35, 46, 17, 13, 29, 48, 32, 11, 9, 33, 37, 20, 38, 44, 53, 23, 41, 22, 26, 3, 49]

Program ended with exit code: 0

这段程序同时也是一个简单高效的发牌程序哦,把DEAL_NUMBER设为一个你需要的、且比TOTAL_NUMBER小的值就可以了,比如把DEAL_NUMBER设为7,那就是一次发7张牌:

A new card list produced:

[8, 32, 12, 20, 33, 45, 25]

Program ended with exit code: 0

如果,你觉得代码还想短一点,Python还逆天地直接提供洗牌函数random.shuffle(list),一句话搞定。可怕吗?就像这样:

random.shuffle(list1)

print("Shuffle directly by random.shuffle function:\n",list1)

-----------

Shuffle directly by random.shuffle function:

[43, 36, 15, 50, 26, 9, 48, 10, 25, 20, 33, 29, 49, 52, 5, 19, 37, 39, 14, 21, 34, 45, 40, 24, 12, 27, 23, 16, 38, 4, 22, 51, 17, 46, 47, 53, 8, 41, 54, 18, 28, 32, 7, 42, 35, 6, 31]

这里是《简单又好玩的Python》专栏,欢迎关注。

源代码文件地址:

参考

python实现洗牌算法_如何高效而完美地洗牌?用Python做很简单相关推荐

  1. 两条平行导线同向电流_如何根据功率计算电流?老师傅说这么做很简单

    第一章 按功率计算电流的口诀 1.用途: 这是根据用电设备的功率(千瓦或千伏安)算出电流(安)的口诀. 电流的大小直接与功率有关,也与电压,相别,力率(又称功率因数)等有关.一般有公式可供计算,由于工 ...

  2. python实现洗牌算法_洗牌算法及 random 中 shuffle 方法和 sample 方法浅析

    对于算法书买了一本又一本却没一本读完超过 10%,Leetcode 刷题从来没坚持超过 3 天的我来说,算法能力真的是渣渣.但是,今天决定写一篇跟算法有关的文章.起因是读了吴师兄的文章 <扫雷与 ...

  3. java利用复循环洗牌算法_随机洗牌算法

    今天偶然看到群里的朋友说道,面试被问如何将扑克牌随机洗牌输出.笔者觉得这道题挺有意思而且挺开放性,有多种不同的实现方式.然后我就随手写了一个算法,仔细一想这个算法的优化空间挺大,于是又写出三种算法. ...

  4. python斗地主出牌算法_斗地主之用蚁群算法整理牌型:如何进行牌力估计

    我们在前面讲到过,各牌手的牌力估计就是我们在用蚁群算法构造最优牌型时的启发性知识.启发性知识其实就是我们利用自己的经验对事物做出的判优性评估,或者说就是对事物价值的判断. 原则上,应用蚁群算法需要用到 ...

  5. python排序链表快速排序算法_八大排序之快速排序算法-python实现

    快排就是折中时间和空间的一个算法,可以说是较为高效的算法,平时用用他没啥大问题. 自己也看到个比较形象生动的例子,为了让大家能够看的比较清楚,我就直接转过来给大家看了哈!但是我使用python实现的: ...

  6. python序列模式的关联算法_关联算法

    以下内容来自刘建平Pinard-博客园的学习笔记,总结如下: 1 Apriori算法原理总结 Apriori算法是常用的用于挖掘出数据关联规则的算法,它用来找出数据值中频繁出现的数据集合,找出这些集合 ...

  7. python实现五大基本算法_算法基础:五大排序算法Python实战教程

    排序是每个算法工程师和开发者都需要一些知识的技能. 不仅要通过编码实现,还要对编程本身有一般性的了解. 不同的排序算法是算法设计如何在程序复杂性,速度和效率方面具有如此强大影响的完美展示. 让我们来看 ...

  8. python中难的算法_一个python的比较难的算法,有懂的人可以进来一下

    问 题 我的需求: 结构数据是这样的: 要求按照这样的公式: 组合一: 时间词+地方词+动词+等级+名词+价格词: 比如 2016年深圳大鹏新区给健康全身检查要多少钱 就是按照这样的公式组合出来的关键 ...

  9. 利用python语言实现分类算法_使用python实现kNN分类算法

    k-近邻算法是基本的机器学习算法,算法的原理非常简单: 输入样本数据后,计算输入样本和参考样本之间的距离,找出离输入样本距离最近的k个样本,找出这k个样本中出现频率最高的类标签作为输入样本的类标签,很 ...

最新文章

  1. php redis 二进制,php-redis扩展
  2. 安卓java修改按钮大小_android弹出activity设置大小的方法
  3. Git复习(四)之解决冲突
  4. 经典C语言程序100例之六三
  5. gtw-050090|执行拦截器时发生异常_执行流程 | 你真的了解Spring AOP的执行顺序吗?...
  6. 前后端分离架构一直没机会实战?1周完成Vue+Core WebApi移动商城实战(含源码)!...
  7. 稀疏数组与二维数组相互转化
  8. Hawtio和Apache JClouds
  9. 攻略:需求评审怎样才能高效易懂?
  10. iphone静态库的加载和调试
  11. 元素之和最接近 0 的区间(部分和)
  12. 恒丰银行微服务架构优化实践
  13. shell之脚本片断
  14. 利用LiveReload插件实现vscode和谷歌浏览器实时刷新
  15. 华为PUSH 日常问题解决方案
  16. 【萌新教学】ESP8266项目初试网页聊天室(附源码)
  17. 链路聚合、Trunk、端口绑定和捆绑简析
  18. python游戏编程
  19. 为什么安装step7时要重启计算机,step7安装提示重启怎么解决
  20. 基于熵权法对TOPSIS法模型的修正

热门文章

  1. 淘宝天猫运营,天天特价活动规则、要求,商家攻略
  2. ChartDirector 6.3(C ++版)教程分享——图标饼图
  3. 500 – 内部服务器错误_无服务器:S3 – S3BucketPermissions –操作不适用于语句中的任何资源...
  4. iOS Gif动画播放
  5. 360度无死角 | Pulsar与Kafka对比全解析
  6. 实验五 网络编程与安全 20162316 刘诚昊
  7. NBIOT开发(一):NBIOT模组以及芯片厂家都有哪些?
  8. NVIDIA/apex报错解决过程
  9. 【ATTCK】守株待兔式的水坑攻击
  10. 通过Shell 脚本向CK集群群分发SQL指令