随机洗牌算法之Knuth-Durstenfeld Shuffle

C#: 实现随机洗牌算法 - Knuth-Durstenfeld Shuffle 其中一个著名的洗牌算法是Knuth-Durstenfeld Shuffle算法,它是由计算机科学家Donald Knuth和Adele Durstenfeld于1969年提出的。通过该算法,你可以在编程中轻松实现随机洗牌操作,用于各种需要元素随机排列的场景。Knuth-Durstenfeld Shuffle算法基于一种思想:通过遍历数组中的每个元素,并将其与随机位置上的元素交换,从而实现洗牌操作。方法接受一个泛型数组作为输入,并使用Knuth-Durstenfeld Shuffle算法对数组进行洗牌。 阅读详情

问题

设计一个公平的洗牌算法

问题分解

  • 首先,必然明确这是一个随机算法

  • 其次,要考虑公平

问题剖析

关于随机

看到随机我们大多数时候想起来的是,把所有的数都放到一个数组里,每次取两个数进行交换,随机 n 次。

那么此时又一个新的问题出现了,n 要取值为多少?如果数组中有 1000 个元素,随机 1000 次,还是 1000000 次?

显然 n 不应该取一个固定的值。而我们通常自然而然会将 n 与数组元素大小相关起来,比如将 n 取为数组大小。那么我们现在再来思考第二个问题,这么做公平吗?

关于公平

细化问题

对于这个问题,显然公平是最重要的。如何定义这个公平是我们要先思考的问题。

在概率学上这并不是一个难的问题,一副牌有 n 个元素,那么最终洗牌能得到的结果排列应一共有 n!个,很显然,公平的洗牌算法应该做到可以等概率地获取到这 n!个结果中的任意一个。

解决实现

暴力方式

在定义完公平后,最简单的实现就是暴力算法了:生成所有的 n!个排列结果,然后随机取出一个作为结果。

这么做绝对是公平的,但是也有个显而易见的问题————算法的复杂度相当高,为 O(n!)。n 个元素一共有 n!种排列,我们要求出所有的排列至少需要 n!的时间。我们都知道指数爆炸,n!在 n>=4 开始,就能以极快的速度超越 2n,毕竟 n!是 n 个数字相乘,除了 1 以外所有的数字都是大于等于 2 的。所以我们在此可以看出虽然暴力算法公平,但其时间复杂度过高。

换位思考

对于公平我们同样可以转变一下思维,对于最后的排列结果,每一个元素都可以等概率的出现在任何一个位置。这个思想逻辑上要更为简单,我们使用一个循环就可以解决:

for (int i=n-1;i>=0;i--){	
    swap(arr[i],arr[rand()%(i+1)])	
}

这个算法已经可以保证每一个位置都能等概率地放置每个元素。从后向前,每次随机[0…i]之间的元素,然后将其与 arr[i]交换。rand()%(i+1)是为了使元素索引保持在 0~i 之间。这就是著名的 Knuth-Durstenfeld Shuffle 随机洗牌算法。

算法原理

接下来我们来证明一下为什么该算法能保证随机的公平性。以下过程将让你感觉到简单到泪流。

我们使用 5 个数字进行模拟说明:


640?wx_fmt=png
knuth-1


我们从最后一位 5 开始,


640?wx_fmt=png
knuth-2


3 出现在最后一个位置的概率显然是1/5,任意一个数出现在最后一位的概率都是1/5的


640?wx_fmt=png
knuth-3


那么最后一位到此为止,我们接下来要管的是前 4 位。

假设出现在倒数第二个位置的是 5,则 5 和 4 进行交换,计算方式中,5 逃出了第一轮的筛选,第一轮有 5 个元素,概率是4/5,但没逃过第二轮的筛选,第二轮有 4 个元素,被选中的概率是1/4。故 5 出现在倒数第二个位置的概率是1/5,如图:


640?wx_fmt=png
knuth-4


后续的计算过程和原理同下图:


640?wx_fmt=png
knuth-5
640?wx_fmt=png
knuth-6
640?wx_fmt=png
knuth-7
640?wx_fmt=png
knuth-8

本期文章就到这里啦,祝大家清凉一夏

640?wx_fmt=jpeg


好看的人才能点640



Ubuntu20.04/Debian10安装向日葵远程控制踩坑实录(附依赖问题解决方案) 本文详细介绍了在Ubuntu 20.04/Debian 10系统上安装向日葵远程控制软件的全过程,重点解决了常见的依赖问题,特别是libwebkitgtk相关错误。通过自动修复、手动修改.deb包依赖和使用兼容层三种解决方案,帮助用户顺利完成安装并优化远程控制体验。 阅读详情

相关推荐

RK3568嵌入式Linux多屏显示开发指南

摘要:本篇RK3568嵌入式Linux多屏显示开发指南详细介绍了基于Qt应用层的实现方案。文章首先概述了技术架构,说明从Qt应用到硬件显示的完整流程。然后提供了两种实现方案:推荐使用Qt内置多屏支持方案,包含完整的C++代码示例和配置文件说明;对于需要精细控制的场景,给出了基于libdrm API的底层实现方案。最后重点讨论了屏幕旋转处理和多屏协同工作模式的关键技术要点,包括扩展桌面、镜像模式等实现方法。

froxy的专栏 1574

常见的两种洗牌算法

该算法的基本思想和 Fisher 类似,每次从未处理的数据中随机取出一个数字,然后把该数字放在数组的尾部,即数组尾部存放的是已经处理过的数字。每次进行洗牌算法后,就把得到的打乱结果对应的频数加一,重复进行 100 万次,如果每种结果出现的总次数差不多,那就说明每种结果出现的概率应该是相等的。这其实就是利用了蒙特卡罗方法:当打的点足够多的时候,点的数量就可以近似代表图形的面积。类似的,我们可以对同一个数组进行一百万次洗牌,统计各种结果出现的次数,把频率作为概率,可以很容易看出洗牌算法是否正确。

天空之蓝的博客 1642

colmap+openMVS稠密重建

简要记录一下colmap+openMVS稠密重建相关使用。

weixin_41631106的博客 2244

使用knuth Durstenfeld Shuffle置乱关键区域

使用knuth Durstenfeld Shuffle置乱关键区域。将关键区域置于整个序列的末尾,从末尾开始逐个交换,完成置换。从结果可以看到,置乱元素比较均匀地撒在了图像之中,效果不错。

计算机视觉之光 332

微型纵向加密在新能源场站中的实战部署与运维避坑指南

本文详细解析了微型纵向加密在新能源场站中的实战部署与运维技巧。通过国密算法SM4实现数据加密,确保新能源场站通信安全,同时提供非侵入式部署方案和运维避坑指南,帮助提升网络稳定性和运维效率。

weixin_30505225的博客 599

angular中访问本地json文件

先在assets文件夹下写一个json文件,这样在打完包之后也可以手动修改json文件内容 1、在需要访问本地json文件的ts文件里面引入 import{HttpClient}from'@angular/common/http'; 2、用ajax请求调用,我这里是用已经封装好的ajax请求调用 gethttp = ()=>{ var self = this self.ajax.getAjax("../../assets/server.json","g...

蜗牛~~ 1830

游戏洗牌算法——常用+详解最优Knuth_Durstenfeld算法

游戏常用算法-洗牌算法

YF云飞的博客 9226

小红书高时效推荐系统背后的技术升级

在小红书 APP 中,推荐系统的实效性对推荐效果有着特别重要的影响,特别是作为 UGC 平台,小红书的推荐系统如果能更快地捕捉用户与笔记之间的变化和联系,就能够给推荐带来更好的效果。在2021年上半年,首页推荐的召回、粗排、精排的主要模块都保持在天级更新的状态,我们通过持续迭代,将召回 CF 渠道、召回索引更新、召回模型/粗精排模型的训练都做到了分钟级更新,为首页推荐的分发效率带来飞跃式提升,并给业务侧带来非常显著的收益。 小红书站内“最近一天内发布的新笔记”在首页的曝光占比一直很高,这段时间更是快速

REDtech_1024的博客 3529

洗牌算法shuffle

将原来数组的数组进行打散,使原数组的某个数在打散后的数组中的每个位置上等概率的出现。很容易想到,需要用到随机数函数,而且应该是一个平均分布的随机数函数,还需要一个不放回的采样的生成模式。(1)random.seed([x]) 伪随机数生成模块。如果不提供 seed,默认使用系统时间。使用相同的 seed,可以获得完全相同的随机数序列,常用于算法改进测试。>>>from random import

风先生的日常专栏 7379

Tiny windows 11 安装与部署

需要注意,安装完后键入 windows 键,输入 update 先更新系统。点击开始,等待完成即可,用户可自定义。

m0_73351035的博客 9049

使用 MATLAB/Simulink + Communications Toolbox + 5G Toolbox,构建一个2×2 MIMO-OFDM通信系统

本文通过Simulink+CommunicationsToolbox构建2×2 MIMO-OFDM通信系统,重点实现信道均衡滤波器(ZF与MMSE)的设计与应用。详细介绍了系统架构、建模步骤(包括信道估计、均衡器实现)和仿真场景设计,通过BER、星座图和EVM对比分析验证了MMSE均衡器在抑制噪声和信号恢复方面的优势。文章总结了MIMO均衡的核心原理与实践经验,并提出了扩展至大规模MIMO、深度学习均衡器等优化方向,为无线通信系统设计提供实用指导。

amy_mhd的博客 127

三种公平洗牌算法

斗地主相信大家都玩过 每次输了之后都要仔细认真的洗牌 确保自己下一局拿到的牌是公平的 对牌局来说,洗牌洗的越乱越随机 那么对每个参与游戏的人来说越公平 小编在编程过程中 经常会遇到这样的操作 给定以下一串数组 怎么得到1-7的乱序全排列呢 起初,我的想法是 任意交换两个元素的位置 循环N次……使劲打乱顺序 这样做每个元素被选中的概率似乎一样 但是这个循环次数N要该怎么取值合理呢 当序列长度过...

qq_44776064的博客 1011

【主题建模】一种基于深度学习的主题建模方法:BERTopic(理论篇)

在我的博客中已经写了很多关于主题建模的内容,当你准备了解 BERTopic 时,默认你已经知道了 LSA、pLSA、NFM、LDA 等传统的主题建模方法。关于主题建模的前置知识我在这里不做赘述,感兴趣的同学可以看看我前几篇博客。学习 BERTopic 需要一定的机器学习基础,让我们一起开始吧!

Data · Model · Agent · Repeat 9896

python——洗牌算法

原地址:洗牌算法 对这个问题的研究始于一次在群里看到朋友发的洗牌面试题。当时也不知道具体的解法如何,于是随口回了一句:每次从剩下的数字中随机一个。过后找相关资料了解了下,洗牌算法大致有3种,按发明时间先后顺序如下: 一、Fisher–Yates Shuffle 算法思想就是从原始数组中随机抽取一个新的数字到新数组中。算法英文描述如下: Write down the numbers from...

他说少年如歌 4314

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

三种洗牌算法shuffle

1. 背景 笔试时,遇到一个算法题:差不多是 在n个不同的数中随机取出不重复的m个数。洗牌算法是将原来的数组进行打散,使原数组的某个数在打散后的数组中的每个位置上等概率的出现,刚好可以解决该问题。 2. 洗牌算法 由抽牌、换牌和插牌衍生出三种洗牌算法,其中抽牌和换牌分别对应Fisher-Yates Shuffle和Knuth-Durstenfeld Shhuffl...

可克技术 1016

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

四种洗牌算法

(1).简单来说就是从原始数据中随机剔除一个数据,并将剔除的数据加入到新的列表中 官方点的话如下: Fisher–Yates Shuffle 算法思想就是从原始数组中随机抽取一个新的数字到新数组中。 算法描述如下: 1. 从还没处理的数组(假如还剩k个)中,随机产生一个[0, k]之间的数字p(假设数组从0开 始); 2. 从剩下的k个数中把第p个数取出; 3. 重复步骤2和3直到数...

qq_39112101的博客 774

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

shuffle算法c语言,C#Shuffle算法(洗牌算法、抽样算法)

Fisher-Yates Shuffle算法1.创建一个新的list2.随机取出当前0-list.Count其中一个数3.把老list当前随机数位置添加到新list4.老list删除这个数5.直到老list.Count=0结束返回public void FisherYatesShuffle(List list){List cache = new List();int currentIndex;wh...

weixin_42691065的博客 1084

洗牌算法

介绍洗牌算法2种,如下: 一、Fisher–Yates Shuffle 算法思想就是从原始数组中随机抽取一个新的数字到新数组中。算法描述如下: (1)从还没处理的数组(假如还剩k个)中,随机产生一个[0, k]之间的数字p(假设数组从0开始); (2)从剩下的k个数中把第p个数取出; (3) 重复步骤2和3直到数字全部取完; (4)从步骤3取出的数字序列便是一个打乱了的数列。 python实现代码...

weixin_43786138的博客 289

The shuffle algorithm

Today I used the python’s API shuffle(random.shuffle) to resort a list and I am wondering the related algorithm so I find some materials。 Fisher-Yates shuffle Write down the numbers from 1 through N....

toyijiu的专栏 213

Shuffle an Array

1. 解析 题目大意,将牌打乱,保证每个元素被交换的概率是一样的。 2. 分析 大多数人想到的解法可能就是直接用rand() % n,然后和当前的元素进行交换,这种随机的交换并不能保证每一张牌都有机会被交换。实际上,这题考察的是Knuth-Durstenfeld Shuffle算法,即每次将最后一张牌和未洗过的随机一张牌进行交换即可,这样就可以保证每张牌都有可能被交换。 class...

Czyaun的博客 172

数组洗牌算法-shuffle

数组洗牌,最近直接的想法是从数组随机取出一个元素,放到另一个数组中,但是这样取出的元素会有重复,必须采取一定的方法保证: 1. 元素不能重复2. 元素被抽取的概率相等,即随机性 数组洗牌经典算法有两种: 1. Fisher-Yates Shuffle(复杂度(n^2)) 数组的删除以及新的copy数组都是耗费时间和空间的。 javascript实现 function Fy...

weixin_30598225的博客 348

与过年相关的两个算法:红包算法和洗牌算法

红包算法和洗牌算法 红包算法 解决红包金额随机生成的问题。 红包分配规则: 所有人抢到金额之和等于红包金额。 每个人至少抢到一分钱。 保证所有人抢到金额的概率相等。 法一:二倍均值法 设剩余红包金额为M,剩余人数为N,金额公式: 每次抢到的金额=(0, M / N X 2) 公式保证每次随机金额的平均值是相等的,不会因为抢红包的先后顺序而造成不公平。 问题:除了最后一次,每次抽到的金额都小...

梦家の博客 629

python抽取随机数_Python 随机数标准库(2) -- shuffle()

Python random包可以用来生成随机数。随机数不仅可以用于数学用途,还经常被嵌入到算法中,用以提高算法效率,并提高程序的安全性。如果想要更加高级的数学功能,可以考虑选择标准库之外的numpy和scipy项目,它们不但支持数组和矩阵运算,还有丰富的数学和物理方程可供使用。本章节主要介绍random.shuffle(),也叫做洗牌函数,它被用来打乱列表元素的顺序。洗牌的意义现实生活中有不少需要...

weixin_39859819的博客 525
上一篇: Gin(四):表单数据提交和模型绑定
下一篇: Gin(六):文件的上传
代码猎奇站
博客等级 码龄7年 39粉丝 29原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值