【问题标题】:Pass Array to Recursive Function While Modifying It C++在修改 C++ 时将数组传递给递归函数
【发布时间】:2023-07-18 01:05:01
【问题描述】:

我有一个递归函数,它在 C++ 中将 2D 数组 作为参数。这个二维数组的内容在这个函数的所有递归调用中是唯一的。

我想在每次进行递归调用之前修改这个数组。如何在不修改两个递归调用的数组的情况下执行此操作,仅针对当前调用?

这是我想要完成的:

void foo(int a[10][10]) {
  // imagine base case above
  // modify array, i.e. set a[2][2] to '5'
  foo(a);
  // modify array i.e. set a[2][2] to '3'
  foo(a);
}

我尝试了以下,导致编译器错误:

void foo(int a[10][10]) {
  // imagine base case above
  foo(a[2][2] = 5);
  foo(a[2][2] = 3);
}

想法是我希望数组在递归调用中独立,例如,我不希望集合a[2][2] = 5 应用于下一个递归调用。从某种意义上说,我希望在应用下一次修改(更改)之前“还原”该数组修改。

如果我只是将int 作为参数传递,这很容易实现。例如,我可以这样做:

void foo(int a) {
  // imagine base case above
  // increase a by 1
  foo(a + 1);
  // decrease a by 4
  foo(a - 4);
}

您可以在这里看到在不影响以下递归调用的情况下进行修改是多么容易。

我的问题是如何使用 array 进行相同的更改。

【问题讨论】:

  • 所以你真正想要的是传递数组按值,所以每个递归调用都有自己的私有副本,它可以随意修改,当递归调用返回原始数组是否未修改?那我建议你改用std::array(或std::vector),因为它们更容易通过值传递。
  • 至于修改位,也许添加一个参数,它是一个调用函数来进行你想要的修改(你可以作为lambda传递)。
  • 能否提供一个使用std::arraystd::vector 的示例?谢谢!
  • 我不确定这是否是您要问的,但似乎您可以这样做void foo(int a[10][10]) { a[2][2] = 5; foo(a); a[2][2] = 3; foo(a); }
  • @coder_jam:您的示例确实不是最好的,因为您更改了相同的元素,因此 cigien 的建议(可能最终恢复const auto old = a[2][2], /*..*/; a[2][2] = old;)可以完成这项工作。

标签: c++ arrays function c++11 recursion


【解决方案1】:

C 数组无法复制,std::array 可以:) 所以我会使用std::array

a[2][2] = 5 改变数组,而 i - 4 不改变整数 i(所以在这种情况下没有什么可丢弃的,与 f(i -= 4) 相反)。

数组上没有运算符,可以轻松自定义, 我们可以为此创建函数或 lambda:

// pass by value
std::array<std::array<int, 10>, 10>
mutated(std::array<std::array<int, 10>, 10> a, int x, int y, int value)
{
    a[x][y] = value;
    return a;
}

void foo(const std::array<std::array<int, 10>, 10>& a) {
  // imagine base case above
  // "modify" array, i.e. set a[2][2] to '5'
  foo(mutated(a, 2, 2, 5));
  // "modify" array i.e. set a[2][2] to '3'
  foo(mutated(a, 2, 2, 3));
}

【讨论】:

    【解决方案2】:

    当您在最后一个示例中调用foo(a + 1) 时,您不是将原始整数而是它的副本传递给函数。要实现与数组类似的功能,您必须创建整个数组的副本,然后在将副本传递给函数之前对其进行修改。

    例子

    void foo(int a[10][10]) {
      // Create two copies of a
      // We cannot simply do 'int b[10][10] = a;', because that would make 
      // b point to the same memory region as a.
      int b[10][10] = {0};
      int c[10][10] = {0};
      for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < 10; ++j) {
          b[i][j] = a[i][j];
          c[i][j] = a[i][j];
        }
      }
    
      // Now that we have two copies of a, we can modify them separately
      // and pass the mto the functions
    
      // modify array, i.e. set [2][2] to '5'
      b[2][2] = 5;
      foo(b);
      // modify array i.e. set [2][2] to '3'
      c[2][2] = 3;
      foo(c);
    

    这个函数会很快消耗内存,因为它会导致无限递归并为每个函数调用创建两个新的 100 元素数组。 a 的手动复制也可以使用 memcpy 完成,但为了清楚起见,我将其写成嵌套 for 循环。

    【讨论】: