我最近在我的一个算法类中被指示使用Knuth的算法来创建存储在malloc'd数组中的排列。
以下是设置:
array是指向包含排列的malloced数组的指针。它最初存储n个值,每个位置保持索引+1。
因此,如果n为10,则数组最初为:
[1,2,3,4,5,6,7,8,9,10]
“rand”变量包含一些从1到n的变量。 (在本例中,1-10)。
交换应该是一个执行位异或交换(XOR)的函数。
最终结果应该是1-n的一些排列。
所以[5,6,2,8,7,4,1,3,10,9]作为一种可能的排列是有效的。
但是,[1,1,5,7,8,2,3,5,5,6]无效,因为它不是排列。它有重复。
但是我无法对这个代码做出正面或反面说明:
for(i = 1; i < n; i++) {
swap(&array[i], &a[rand]);
}
所以我们从数组的第二个元素开始。 (i = 1)
然后我们尝试对两个参数进行异或运算:
首先:&amp; array [i]
这是指向malloced数组的指针的地址。 (一个双指针,对吗?)
第二个参数完全相同。指向malloced数组的指针的地址。
我应该如何以及为什么要对地址进行异或?
我不理解什么?
感谢您的帮助!
答案 0 :(得分:4)
首先,交换不应该按位排序或。它应该交换。
通常,写的是:
void swap(int *a, int *b)
{
int t=*a;
*a=*b;
*b=t;
}
但是使用XOR的技巧并不需要额外的变量。您可以像这样实现交换:
void swap(int *a, int *b)
{
*a^=*b;
*b^=*a;
*a^=*b;
}
这可能是某人在交换中进行异或的意思。
其次,rand的范围从0到i,而不是1到n,你想要一个无偏的随机排列。
鉴于rand(x)在[0,x]中返回一个数字,你需要这样的东西:
for (int i=n-1; i>0; --i)
{
j = rand(i);
if (i!=j)
{
swap(&array[i],&array[j]);
}
}
它的工作方式很简单:对于每个数组[i],它从那些尚未被选中的中随机选择 。