直接在二维数组中执行 fisher - yates shuffle
Performing fisher - yates shuffle directly in a 2D array
我一直在尝试直接对二维数组的前 N 个元素执行部分 fisher-yates 洗牌,但没有成功。我知道我可以将 2D 数组转换为 1D 数组,执行随机播放然后将其转回去,但如果可能的话我想避免这种情况。
我的实现中的问题是,我认为虽然我还没有证明,但我的数组每一行的最后一个元素没有正确打乱。事实上,假设我有一个 m*n
数组,其中第一个 N
等于 1,其余 m*n - N
等于 0。当我执行第一个 [=12] 的随机播放时=] 数组的元素,大约有 67% 的时间每行末尾的元素:array[i][end]
等于 1,这在我看来太多次了。
这是我的实现以及可以运行显示问题所在的驱动程序代码:
void swap(int **a, int i, int j, int iNew, int jNew)
{
int temp = a[i][j];
a[i][j] = a[iNew][jNew];
a[iNew][jNew] = temp;
}
void fisher_yates_shuffle(int n, int nbLines, int nbColumns, int **a)
{
for (int i = 0; i < nbLines; i++)
{
for (int j = 0; j < nbColumns; j++)
{
swap(a, i, j, i+rand()%(nbLines-i), j+rand()%(nbColumns -j)); // swap element with random later element
n--;
if(n<=0)
break;
}
if(n<=0)
break;
}
}
int main(int argc, char const *argv[])
{
int count1 = 0, count2 = 0, count3 = 0, count4 = 0, N = 10, k = 100000;
srand(time(NULL));
//Short example of a 5 by 5 array, with N = 10 first elements equal to 1
//that need to to be shuffled among all of its elements.
while(k > 0)
{
//allocate
N = 10;
int **a = (int**)malloc(sizeof(int*) * 5);
for(int i = 0; i < 5; i++)
a[i] = (int*)malloc(sizeof(int) * 5);
//initialize
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
if(N > 0)
a[i][j] = 1;
else
a[i][j] = 0;
N--;
}
}
//shuffle
fisher_yates_shuffle(10, 5, 5, a);
//count how many times the last element of each row is equal to 1.
if(a[1][4] == 1)
count1++;
if(a[2][4] == 1)
count2++;
if(a[3][4] == 1)
count3++;
if(a[4][4] == 1)
count4++;
//destroy memory allocated.
for(int i = 0; i < 5; i++)
free(a[i]);
free(a);
k--;
}
//print approximate results.
printf("%d %d %d %d\n", (count1 * 100)/100000, (count2 * 100)/100000, (count3 * 100)/100000, (count4 * 100/100000));
return 0;
}
我知道它看起来不太好,必须有更有效的方法来做到这一点。也许有一种不同的、同样有效的算法来像这样打乱二维数组的前 N 个元素?
扩展我之前的评论,你可以在一个循环中随机播放你的 "array":
void fisher_yates_shuffle(int n, int nbLines, int nbColumns, int **a)
{
for (int i = 0; i < n; i++)
{
int j = i + rand() % (nbLines * nbColumns - i);
swap(a, i / nbColumns, i % nbColumns, j / nbColumns, j % nbColumns);
}
}
请注意,在 C 中有更好的方法来实现和传递矩阵,并且您的交换函数应该 return void
,而不是 int
。
我一直在尝试直接对二维数组的前 N 个元素执行部分 fisher-yates 洗牌,但没有成功。我知道我可以将 2D 数组转换为 1D 数组,执行随机播放然后将其转回去,但如果可能的话我想避免这种情况。
我的实现中的问题是,我认为虽然我还没有证明,但我的数组每一行的最后一个元素没有正确打乱。事实上,假设我有一个 m*n
数组,其中第一个 N
等于 1,其余 m*n - N
等于 0。当我执行第一个 [=12] 的随机播放时=] 数组的元素,大约有 67% 的时间每行末尾的元素:array[i][end]
等于 1,这在我看来太多次了。
这是我的实现以及可以运行显示问题所在的驱动程序代码:
void swap(int **a, int i, int j, int iNew, int jNew)
{
int temp = a[i][j];
a[i][j] = a[iNew][jNew];
a[iNew][jNew] = temp;
}
void fisher_yates_shuffle(int n, int nbLines, int nbColumns, int **a)
{
for (int i = 0; i < nbLines; i++)
{
for (int j = 0; j < nbColumns; j++)
{
swap(a, i, j, i+rand()%(nbLines-i), j+rand()%(nbColumns -j)); // swap element with random later element
n--;
if(n<=0)
break;
}
if(n<=0)
break;
}
}
int main(int argc, char const *argv[])
{
int count1 = 0, count2 = 0, count3 = 0, count4 = 0, N = 10, k = 100000;
srand(time(NULL));
//Short example of a 5 by 5 array, with N = 10 first elements equal to 1
//that need to to be shuffled among all of its elements.
while(k > 0)
{
//allocate
N = 10;
int **a = (int**)malloc(sizeof(int*) * 5);
for(int i = 0; i < 5; i++)
a[i] = (int*)malloc(sizeof(int) * 5);
//initialize
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
if(N > 0)
a[i][j] = 1;
else
a[i][j] = 0;
N--;
}
}
//shuffle
fisher_yates_shuffle(10, 5, 5, a);
//count how many times the last element of each row is equal to 1.
if(a[1][4] == 1)
count1++;
if(a[2][4] == 1)
count2++;
if(a[3][4] == 1)
count3++;
if(a[4][4] == 1)
count4++;
//destroy memory allocated.
for(int i = 0; i < 5; i++)
free(a[i]);
free(a);
k--;
}
//print approximate results.
printf("%d %d %d %d\n", (count1 * 100)/100000, (count2 * 100)/100000, (count3 * 100)/100000, (count4 * 100/100000));
return 0;
}
我知道它看起来不太好,必须有更有效的方法来做到这一点。也许有一种不同的、同样有效的算法来像这样打乱二维数组的前 N 个元素?
扩展我之前的评论,你可以在一个循环中随机播放你的 "array":
void fisher_yates_shuffle(int n, int nbLines, int nbColumns, int **a)
{
for (int i = 0; i < n; i++)
{
int j = i + rand() % (nbLines * nbColumns - i);
swap(a, i / nbColumns, i % nbColumns, j / nbColumns, j % nbColumns);
}
}
请注意,在 C 中有更好的方法来实现和传递矩阵,并且您的交换函数应该 return void
,而不是 int
。