是否可以按随机顺序迭代数组?

时间:2021-01-04 00:00:44

标签: c++ arrays loops

所以,假设我有一个数组:

int arr[5];

不是从 0 到 4 遍历数组,是否可以按随机顺序进行,并且迭代器不会两次遍历同一位置?

2 个答案:

答案 0 :(得分:2)

以下所有假设您想在 O(1) 空间中实现迭代 - 不使用例如索引的辅助数组,您可以对其进行洗牌。如果你能负担得起 O(n) 的空间,那么解决方案相对容易,所以我假设你只能负担得起 O(1)。

要以随机方式迭代数组,您可以制作一个随机数生成器,并将其输出用作数组的索引。您不能以这种方式使用标准 RNG,因为它们可能会过早地两次输出相同的索引。然而,RNG 的理论相当广泛,至少有两种类型的 RNG 对其周期有保证。

使用这些理论思想:

  1. 选择一个数字 N ≤ n(其中 n 是数组的大小),但不能大于 n,这样就可以构建一个周期为 N 的 RNG
  2. 调用您的 RNG N 次,因此它会生成从 0 到 N-1 的数字排列
  3. 对于每个数字,如果它小于数组的大小,则输出具有该索引的数组元素

在给定周期内制作 RNG 的技术可能太烦人而无法在代码中实现。因此,如果您事先知道数组的大小,您可以选择 N = n,并手动创建您的 RNG(分解 n 或 n+1 将是第一步)。如果您不知道数组的大小,请为 N 选择一些易于使用的数字,例如一些合适的 2 的幂。

答案 1 :(得分:1)

正如评论中提到的,您可以通过多种方式来做到这一点。最明显的方法是仅 shuffle 范围,然后对其进行迭代:

std::shuffle(arr, arr + 5);

for (int a : arr) 
  // a is a new random element from arr in each iteration

这当然会修改范围,这可能不是你想要的。


对于不修改范围的选项:您可以生成一系列索引,对这些索引进行混洗并使用这些索引将这些索引编入范围:

int ind[5];
std::iota(ind, ind + 5, 0);
std::shuffle(ind, ind + 5);

for (int i : ind)
  // arr[i] is a new random element from arr in each iteration

您还可以实现一个自定义迭代器,该迭代器以随机顺序在一个范围内迭代而不会重复,尽管这对于您尝试实现的功能来说可能有点过头了。尝试一下,了解它是如何工作的,这仍然是一件好事。