基本概念
等概率将将一个数组N打乱,概率每次都是1/N,加上
方法一
全局洗牌, 从 0到N-1的数组下标,每次随机产生两个0到 N-1之间的数,进行交换
void get_rand_number(int array[], int length)
{
int index;
int value;
int median;
if(NULL == array || 0 == length)
return ;
/* 每次发牌的时候任意分配待交换的数据 */
for(index = 0; index < length; index ++){
value = rand() % length;
(在这里要取余数,主要是 )
median = array[index];
array[index] = array[value];
array[value] = median;
}
## j
局限性
多次重复洗牌,
Knuth Shuffle洗牌算法
局部洗牌, 从比如选定位置N-1,随机产生0到N-2之间的一个数,将下标为该数的值与N-1上面的位置进行交换(只考虑为洗好的牌)
,N-1位置上面的数就洗好了,洗一次就不考虑
for i 从 N-1 到 1,
随机数 0到 i(可以等于i) 随机产生一个数 j
交换i和j之间连个鬼数
首先我们生成一个大小为54的数组,数组排列为1~54
a)同样,首先我们生成一个大小为54的数组,数组排列为1~54
b)索引牌从1开始,到54结束。这一次索引牌只和剩下还没有洗的牌进行交换, value = index + rand() %(54 - index
c)等到所有的索引牌都洗好之后,一副牌就弄好了
void get_rand_number(int array[], int length)
{
int index;
int value;
int median;
if(NULL == array || 0 == length)
return ;
/* 发牌的时候对于已经分配的数据不再修改 */
for(index = 0; index < length; index ++){
value = index + rand() % (length - index);
median = array[index];
array[index] = array[value];
array[value] = median;
}
}
Knuth Shuffle
每次从未处理的数组中随机取一个元素,然后把该元素放到数组的尾部,即数组的尾部放的就是已经处理过的元素,这是一种原地打乱的算法,每个元素随机概率也相等,时间复杂度从 Fisher 算法的 O(n2)提升到了 O(n)
选取数组(长度n)中最后一个元素(arr[length-1]),将其与n个元素中的任意一个交换,此时最后一个元素已经确定
选取倒数第二个元素(arr[length-2]),将其与n-1个元素中的任意一个交换
重复第 1 2 步,直到剩下1个元素为止