洗牌算法直观的来说,是将一幅有序的扑克牌经过处理后变成乱序的。这个处理的过程就是洗牌算法了,当然这里的扑克牌也许是其他的数据等等,算法要保证乱序后的数据和之前的一模一样,只是顺序不同而已。下面就针对不同形式的洗牌算法给出代码。
有54张牌,乱序存储在一个整型数组中arr[54]。一副牌就用1,,,54这54个数字代替。
//从无到有随机生成一副牌序
void MyShuffle_NonToSome(int arr[] ,int num)
{
srand(time(NULL));
int pos,temp = 0;
memset(arr,0,sizeof(int) * num);
for (int idx = 1; idx <= 54; idx++)
{
do
{
pos = rand() % num;
} while (arr[pos] != 0);
arr[pos] = idx;
}
}
这种方式下,首先是两层循环的嵌套,本来就降低了效率,而且随着数组中数据的增多里层循环执行的次数也越来越多。
rand()的定义:
srand()的定义:
针对一个已经给出的有序的序列,可以采用随机交换两个数组元素的方式实现乱序。至于交换的次数由个人来定,交换的次数越多就越接近乱序,就越有效。
//基于N次交换的随机算法,固定循环次数
void MyShuffle_Ns_Swap(int arr[], int num)
{
int pos1,pos2;
int temp = 0;
srand(time(NULL));
for (int idx = 0; idx < num; idx++)
{
pos1 = rand() % num;
pos2 = rand() % num;
if (pos1 != pos2)
{
temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
}
}
这种方法循环次数一定,交换次数一般情况下就是数据的个数,简单明朗
还有一种和这个类似,第一次在0到53之间生成一个随机数randomNum,将其(arr[randomNum])作为下标和数组最后一个(arr[53])互换位置;然后缩小随机范围,在0到52之间随机一个数字将其作为下标arr[randomNum]和arr[52]互换位置,经过54次交换也可以达到乱序效果。
//从后往前缩小随机范围,将每一次随机到的值以此从后往前存放,固定循环次数
void MyShuffl_CutRange(int arr[], int num)
{
//初始化随机数生成器种子
srand(time(NULL));
int pos,temp = 0;
unsigned int size = num;
for (int idx = num-1; idx >= 0; idx--)
{
pos = rand() % size--;
if (pos != idx)
{
temp = arr[pos];
arr[pos] = arr[idx];
arr[idx] = temp;
}
}
}