目录
前言
这是我的第一篇csdn博客,以此来记录一个大一计算机学生,从大一到大三秋招的编程学习历程,并督促自己,希望能一点点进步,不要磨灭了那份心气,fighting!
2025.9.25
笔者目前打算在国庆假期结束前学习完C语言基础,由于笔者是从零开始的计算机学习之路,不像诸多大佬一样在中学时就有算法基础,所以笔者开始写的东西可能比较简单qwq,只是每次学习后的一次正反馈hhh。
一、什么是Fisher-Yates?
简单来说,是将一组元素随机打乱(将两个不同的元素交换),类似于洗牌的效果,所以又叫洗牌算法。这种方法能保证洗牌的随机性和均匀性。
Fisher-Yates 算法的核心思想是: 每次从未处理的元素中随机选择一个,然后与未处理部分的最后一个元素交换,且从数组的末尾开始倒序遍历。
-
随机性:由于采用了随机数生成器和随机种子,即C语言中的rand( )函数和srand(time(NULL))种子,保证了这种方法的随机性.
-
均匀性,即每个元素在每个位置出现的概率是相等的,可以从数学概率的角度来解释(贝叶斯公式)
我们以一个长度为 n 的数组为例,证明每个元素出现在任意位置的概率都是 1/n:
1.
对于最后一个位置 :
- 第一次迭代时,我们从整个数组中随机选择一个元素放到最后位置
- 任何特定元素被选中的概率是 1/n
2.
对于倒数第二个位置 :
- 我们从未处理的前 n-1 个元素中随机选择一个
- 一个特定元素出现在这里的概率 = (该元素未被选中到最后位置的概率) × (该元素被选中到倒数第二位置的概率)
- 计算:(n-1)/n × 1/(n-1) = 1/n
二、洗牌算法的运用
下面以C语言中打乱数组中的数据这个简单的问题为例子。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main()
{
int arr[5] = {1,2,3,4,5};
int len = sizeof(arr) / sizeof(int);
srand(time(NULL));
for (int i = len-1; i >=0; i--)
{
int num = rand() % (i+1);
int temp = arr[i];
arr[i] = arr[num];
arr[num] = temp;
}
printf("打乱后的数组/n");
for (int i = 0; i < len; i++)
{
printf("%d\n", arr[i]);
}
return 0;
以temp作为中间量进行交换,可以保证数据不重复。注意最后打印打乱后的数组要在循环外,不然会出现重复。
为什么是倒序遍历?
避免重复选择,提高算法效率。实际上"正序Fisher-Yates变体"也是可行的。
总结
Fisher-Yates 洗牌算法是一种经典的洗牌算法,能够在 O(n) 时间内将数组随机打乱,并确保所有排列的生成是等概率的。它广泛应用于随机排序、游戏设计和数据抽样等领域,是随机算法中的一个基础算法。
8167

被折叠的 条评论
为什么被折叠?



