试图理解Knuth的排列算法

时间:2016-03-05 20:36:46

标签: c arrays algorithm pointers knuth

我最近在我的一个算法类中被指示使用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数组的指针的地址。

我应该如何以及为什么要对地址进行异或?

我不理解什么?

感谢您的帮助!

1 个答案:

答案 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],它从那些尚未被选中的中随机选择