美文网首页
Fisher Yates 洗牌算法

Fisher Yates 洗牌算法

作者: JeremyL | 来源:发表于2022-05-09 20:07 被阅读0次

Fisher–Yates shuffle是一种基于有限序列产生随机排列的算法。因为每次抽取每个元素都是等概率的,所以该算法产生一个无偏排列:每个排列的可能性相等。

# 1. Fisher–Yates shuffle原始算法

Fisher–Yates shuffle最开始描述在Ronald Fisher and Frank YatesStatistical tables for biological, agricultural and medical research一书中。

  1. 1到N的数字;
  2. 从1到N之间随机抽取一个整数;
  3. 从1到N的数字中删除第K个元素,并将其放置到结果中
  4. 重复步骤2和3,直至元素耗尽
  5. 结果中新的排列就是原来元素的随机排列
  • 例子:

A到H的排列


image.png

抽取1-8之间的随机数

保存对应位置的元素到结果,并删除原始排列中的元素


image.png
image.png
image.png

# 2. Fisher–Yates shuffle现代算法

原始方法会花费不必要的时间来计算上面第3步中剩余的数字;新方法做出改进,就是将挑选的元素和最后一个元素进行互换。

-- To shuffle an array a of n elements (indices 0..n-1):
for i from n−1 downto 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

相反方向的排列

-- To shuffle an array a of n elements (indices 0..n-1):
for i from 0 to n−2 do
     j ← random integer such that i ≤ j < n
     exchange a[i] and a[j]
  • 例子:

A到H的排列


image.png

抽取1-8之间的随机数

保存对应位置的元素到结果,并删除原始排列中的元素


image.png
image.png
image.png

# 3. 实现

#include <stdlib.h>
#include <time.h>
#include <vector>
#include <iostream>
#include <numeric>
using namespace std;

void swap (int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

void printArray (int arr[], int n)
{
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
    cout << "\n";
}

void randomize (int arr[], int n)
{
    unsigned int seed =1;
    srand (seed);

    for (int i = n - 1; i >= 0; i--)
    {
        int j = rand() % (i + 1);

        swap(&arr[i], &arr[j]);
    }
}

int main()
{

    int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int n = sizeof(arr) / sizeof(arr[0]);

    printArray(arr, n);
    randomize (arr, n);
    printArray(arr, n);

    return 0;
}

//0 1 2 3 4 5 6 7 8 9 
//9 8 4 2 0 6 5 1 7 3 
#include <stdlib.h>
#include <time.h>
#include <vector>
#include <iostream>
#include <numeric>
using namespace std;
    
void printFun(std::vector<int> vec)
{
    for (int i = 0; i < vec.size(); i++)
    {cout << vec[i] << " ";}    
    cout << "\n";
}

std::vector<int> randomize (int range, int n, unsigned int seed)
{
    //定义feature index
    std::vector<int> vec(range);
    std::iota(vec.begin(), vec.end(), 0);
    
    srand (seed);
    std::vector<int> vec2;
    
    int len = vec.size()-1;
    for (int i = n; i > 0; i--)
    {
        int j = rand() % (len+1);
        vec2.push_back(vec[j]); 
        std::swap(vec[j], vec[len]);
        len = len-1;
    }
    return vec2;
}

int main()
{
    std::vector<int> vec(11);
    std::iota(vec.begin(), vec.end(), 0);
    
    printFun(vec);
    std::vector<int> vec2 = randomize (vec.size(),11,1);
    printFun(vec2);

    return 0;
}

//0 1 2 3 4 5 6 7 8 9 10 
//6 10 0 3 1 9 5 8 7 4 2 

# 原文:

Fisher–Yates shuffle

Shuffle a given array using Fisher–Yates shuffle Algorithm

相关文章

  • Fisher–Yates 洗牌算法,es5

    //Fisher–Yates 洗牌算法 shuffle(arr) { var i = arr.length,...

  • Fisher Yates 洗牌算法

    Fisher–Yates shuffle是一种基于有限序列产生随机排列的算法。因为每次抽取每个元素都是等概率的,所...

  • 算法题目4:数组打乱顺序

    (一)Fisher–Yates shuffle 洗牌算法是最完美乱序的算法/方法之一. (二) sort这不是真正...

  • Fisher–Yates shuffle洗牌算法

    最近需要做一个小游戏,游戏的第一个需求就是要实现一个算法:随机打乱一个数组,也可以称之为洗牌。 现实生活中,洗牌的...

  • Fisher–Yates Shuffle洗牌算法

    如果你想跟朋友一起玩德州扑克的话,你应该先洗牌,以随机的牌序来确保一个公平的游戏。但是怎么做呢? 有一个简单而有效...

  • Fisher–Yates shuffle洗牌算法

    背景 如何将一个数组中的元素随机打乱?如何又却能确保一个元素的位置不变,将其他元素位置打乱? 问题:用js实现一个...

  • Fisher–Yates shuffle 洗牌算法

    Fisher–Yates shuffle 洗牌算法 我们简单借助图形来理解(图片来源于网络) 首先我们有一个已经排...

  • 打乱一个有序数组

    sort方法 Fisher–Yates shuffle洗牌算法 首先我们有一个已经排好序的数组 1.从数组末尾开始...

  • 实现洗牌算法

    洗牌算法 Fisher–Yates随机置乱算法也被称做高纳德置乱算法,通俗说就是生成一个有限集合的随机排列。Fis...

  • Fisher-Yates-Knuth洗牌算法

    给定一副扑克牌,要求将排均匀的打乱 算法思路: 将扑克牌依次存储到数组中,将数组分成两部分,前半部分是已经打乱顺序...

网友评论

      本文标题:Fisher Yates 洗牌算法

      本文链接:https://www.haomeiwen.com/subject/cbxkurtx.html