Fisher–Yates shuffle 算法详解:给定数组的乱序

1、算法思想
根据维基百科解释:TheFisher–Yates shuffle is analgorithm for generating a random permutation of a finite sequence—in plain terms, the algorithm shuffles the sequence. The algorithm effectively puts all the elements into a hat; it continually determines the next element by randomly drawing an element from the hat until no elements remain. The algorithm produces anunbiased permutation: every permutation is equally likely. The modern version of the algorithm is efficient: it takes time proportional to the number of items being shuffled and shuffles themin place.

    Fisher–Yates shuffle是对有限序列生成一个随机排列的算法,所有的排列是等概率的,该算法是无偏的、高效的,算法的时间正比于乱序的数组。思想如下:

To shuffle an array a of n elements (indices 0…n-1):

for i from n-1 downto 0://数组i从n-1到0循环执行n次

    random_choice j <-- random integer such that 0 ≤j ≤i;//生成一个0到n-1之间的随机索引

    exchange a[j] and a[i]  //将交换之后剩余的序列中最后一个元素与随机选取的元素交换

该算法就是python中random.shuffle函数的具体实现

import random

a = [1,2,3,4,5,6,7,8,9]

random.shuffle(a)

a

[9, 1, 3, 4, 6, 8, 7, 5, 2]

2、举例
各列含义:范围、当前数组随机交换的位置、剩余没有被选择的数、已经随机排列的数

第一轮:从1到8中随机选择一个数,得到6,则交换当前数组中第8和第6个数

第二论:从1到7中随机选择一个数,得到2,则交换当前数组中第7和第2个数

下一个随机数从1到6中摇出,刚好是6,这意味着只需把当前线性表中的第6个数留在原位置,接着进行下一步;以此类推,直到整个排列完成。

截至目前,所有需要的置乱已经完成,所以最终的结果是:7 5 4 3 1 8 2 6

3、python代码实现
给定产生随机数的函数random.int与数组arr,实现shuffle函数功能。

import numpy as np
import random
“”"
def Fisher_yate_shuffle(arr):
length=len(arr)
for i in range(length)[::-1]:#倒序遍历
j=random.randint(0,i) #随机选取0和i之间的一个数j
#exchange arr[i] and arr[j]
temp=arr[i]
arr[i]=arr[j]
arr[j]=temp
return arr

if name==‘main’:
array = np.arange(1,10)
shuffle = Fisher_yate_shuffle(array)
print(shuffle)
“”"

def rand():
return random.randint(0,100000000)

#当序列的长度小于我们随机的数,如何映射到指定范围

def Fisher_yate_shuffle(arr):
length=len(arr)
a = range(length) # 给定数组的长度列表
a.reverse() # 倒序方式进行遍历
for i in a: # 从大到小取索引
#j=random.randint(0,i)
j = rand()
j = j % length #取余操作进行映射
#exchange arr[i] and arr[j]
temp=arr[i]
arr[i]=arr[j]
arr[j]=temp
return arr

if name==‘main’:
array=np.arange(1,200)
shuffle = Fisher_yate_shuffle(array)

print(len(set(shuffle)))
print(len(shuffle))

4、Pencil-and-paper method
该方法与fisher_yates类似,只不过要重新开辟一个新数组,相当于循环通过随机选取原数组的值放到新数组中。

代码实现如下:

def pencil_paper_shuffle(arr):
arr = list(arr)
new_arr = []
length = len(arr)
print(length)
while(length>0):
j = random.randint(0,length-1)
new_arr.append(arr[j])
arr.remove(arr[j])
#arr[j] = arr[length-1]
length -=1
print(‘arr is {}—new_arr is {}’.format(arr, new_arr))
return new_arr

if name==‘main’:
array=np.arange(1,10)
shuffle = pencil_paper_shuffle(array)
print(shuffle)

————————————————
版权声明:本文为CSDN博主「spirits_of_snail」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qikaihuting/article/details/78224690

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值