【问题标题】:Recursive function that uses static var使用静态变量的递归函数
【发布时间】:2019-10-05 23:37:26
【问题描述】:

所以这个函数似乎需要使用静态函数,我意识到的问题是在递归函数结束之前没有办法重置静态var。有没有一种我没有看到的方法,或者有没有不使用静态变量的好方法。

这个函数的目标是首先用奇数变量填充一个数组,所以假设你称之为 fillAryOddFirst(ary, 13) 那么数组将按以下顺序填充 [13、11、9、7、5、3、1、2、4、6、8、12]

void fillAryOddFirst(int ary[], int size) {
    static int pos;
    if (size <= 0) {
        return;
    }
    if(size % 2 != 0){
        ary[pos] = size;
        pos++;
    }
    fillAryOddFirst(ary, size-1);
    if(size % 2 == 0 ){
        ary[pos] = size;
        pos++;
    }    
    return;
}

【问题讨论】:

  • 你真正想做什么?有各种各样的方法可以解决这个问题——其中大多数不需要递归或静态变量。问题的约束是什么?
  • 可悲的是学校作业,所以我必须递归地做这个问题
  • 好的,除了递归,问题的约束是什么?您是否需要使用该静态变量?你能向函数传递更多参数吗?
  • 否,不需要静态变量。唯一的限制是用从 1 到大小的数字填充数组,奇数首先从大到小,然后从最小到最大,当然它必须递归完成
  • "...有没有不使用静态变量的好方法。" - 是的。 “pos”可以成为围绕这个递归函数的类包装器的数据属性。

标签: c++ function recursion static


【解决方案1】:

不,无法重置本地 static 变量。

如果你希望能够重置它,你唯一的选择是让它成为一个全局变量,即将它的声明移到函数之外。


另一种可能性是使其成为您通过引用传递的参数:

void fillAryOddFirst(int ary[], int size, int &pos)
{
    if (size <= 0)
    {
        return;
    }
    if (size % 2 != 0)
    {
        ary[pos] = size;
        pos++;
    }
    fillAryOddFirst(ary, size - 1, pos);
    if(size % 2 == 0 )
    {
        ary[pos] = size;
        pos++;
    }    
}

void fillAryOddFirst(int ary[], int size)
{
    int pos = 0;
    fillAryOddFirst(ary, size, pos);
}

【讨论】:

  • 我真的只是回到这里说我用你刚刚发布的确切方式想通了哈哈。不过谢谢!
  • 我觉得也应该有一种通过价值传递的方法,但既然你已经在这里有了这个很好的答案,我不想弄清楚如何。
【解决方案2】:

如果size 是奇数,则写入第一个元素。如果是偶数,则写入最后一个元素。在任何一种情况下,递归地“关注”剩余的子数组:

void fillAryOddFirst(int ary[], int size) {
    if(size > 0) {
        if(size % 2 == 1) {
             // +---+---|...|---+
             // | s | ? |???| ? |
             // +---+---|...|---+
             // ^ ary           ^ ary + size
             //     ^ ary + 1   ^ (ary + 1) + (size - 1)
             //     \-----------/ focus on this range
             ary[0] = size;
             fillAryOddFirst(ary + 1, size - 1);
        } else /*if(size % 2 == 0)*/ {
             // +---|...|---+---+
             // | ? |???| ? | s |
             // +---|...|---+---+
             // ^ ary           ^ ary + size
             // |           ^ ary + (size - 1)
             // \-----------/ focus on this range
             ary[size - 1] = size;
             fillAryOddFirst(ary, size - 1);
        }
    }
}

写成一个循环,那就是

void fillAryOddFirst(int ary[], int size) {
    for(; size > 0; size--) {
        if(size % 2 == 1) *ary++ = size;
        else ary[size - 1] = size;
    }
}

也就是说,您将遍历 size 直至 1,并将赔率放在开头,将偶数放在结尾。

【讨论】:

    【解决方案3】:

    “...有没有不使用静态变量的好方法。”

    是的。将函数包装在一个类中。

    在一个类中,“static int pos”函数变量可以成为包装器的简单数据属性。

    以下是几个代码示例。

    1) 首先是证明您的问题是可重复的。

    2) 一个简单的类包装器,称为类 FillAryOddFirstClass_t。该功能与您原来的功能非常相似,但 pos 不是静态的。

    3) 一个简单的 Functor 包装器,称为类 FillAryOddFirstFunctor_t。函子有一个更简单的调用。

    4) 因为您已将这篇文章声明为 C++ 问题,所以第 4 项使用向量而不是数组——但请注意,代码使用与第 2 项相同的类来运行递归,FillAryOddFirstClass_t,它需要一个数组!向量数据驻留在动态内存中,通过指定“&iVec[0]”(而不是ary),传递的地址是堆中向量数据的开始元素。

    5) 这是带有附加功能的第 2 项。类 FillAryOddFirstClass2_t 内部复杂,有 2 个报告函数。报告函数构建字符串以显示递归/递归执行的进度。


    #include <iostream>
    using std::cout, std::endl; // c++17
    
    #include <iomanip>
    using std::setw;
    
    #include <string>
    using std::string, std::to_string;
    
    #include <vector>
    using std::vector;
    
    
    // original - with static
    void fillAryOddFirst ( int ary[], int size )
    {
       static int pos;   // <<<<<<<<<<<<<<< static
    
       if (size <= 0) { return; }
    
       if(size % 2 != 0) { ary[pos] = size; pos++; }
    
       fillAryOddFirst(ary, size-1);
    
       if(size % 2 == 0 ) { ary[pos] = size; pos++; }
    
       return;
    }
    
    // class wrapper 
    class FillAryOddFirstClass_t  // UDT - user defined type
    {
       int pos;    // <<<<<<<<<<<<<<<  not static, a simple attribute
    
    public:
       FillAryOddFirstClass_t() : pos (0) { }
       ~FillAryOddFirstClass_t() = default;
    
       void fillAryOddFirst ( int ary[], int indx )
          {
             if (indx <= 0) { return; }
    
             if(indx % 2 != 0) { ary[pos] = indx; pos++; }
    
             fillAryOddFirst(ary, indx-1);
    
             if(indx % 2 == 0 ) { ary[pos] = indx; pos++; }
    
             return;
          }
    };
    
    // Functor wrapper
    class FillAryOddFirstFunctor_t // UDT (user defined type)
    {
       int pos;    // <<<<<<<<<<<<<<<  not static
    
    public:
       // default ctor and dtor do nothing, cost nothing
    
       void operator()( int ary[], int indx) // functor entry
          {
             pos = 0;  // init
             fillAryOddFirst(ary, indx);
             return;
          }
    
    private:
       void fillAryOddFirst( int ary[], int indx) 
          {
             if (indx <= 0) { return; }
    
             if(indx % 2 != 0) { ary[pos] = indx; pos++; }
    
             fillAryOddFirst(ary, indx-1);
    
             if(indx % 2 == 0 ) { ary[pos] = indx; pos++; }
    
             return;
          }
    };
    
    // class wrapper, with cout progress indicator
    class FillAryOddFirstClass2_t  // UDT
    {
       int    pos;    // <<<<<<<<<<<<<<<  no static
       size_t sz = 10;
    
    public:
       FillAryOddFirstClass2_t() : pos (0) { }
       ~FillAryOddFirstClass2_t() = default;
    
       void fillAryOddFirst ( size_t rLvl, int ary[], int indx )
          {
             if (indx <= 0) {
                cout << "\n\n" << setw(11)  << " " << "recurse end - decurse begins\n";
                return;
             }
    
             if(indx % 2 != 0) { ary[pos] = indx; pos++; }
    
             cout << rprtR   (rLvl,   ary); // recurse report
    
             fillAryOddFirst (rLvl+1, ary, indx-1);
    
             cout << rprtD   (rLvl,   ary); // decurse report
    
             if(indx % 2 == 0 ) { ary[pos] = indx; pos++; }
    
             return;
          }
    
       // report recurse
       string rprtR ( size_t rLvl, int ary[])
          {
             std::stringstream ssOut;
             ssOut << "\n  " << setw(4) << rLvl
                   << "   " << show(ary) << ' ';
             return ssOut.str();
          }
    
       // report decurse
       string rprtD ( size_t rLvl, int ary[])
          {
             std::stringstream ssOut;
             ssOut << "\n  " << setw(4) << rLvl
                   << "   " << show(ary) << '_';
             return ssOut.str();
          }
    
       string show(int ary[])
          {
             std::stringstream ssOut;
             for (uint i=0; i<(sz-1); ++i)
                if (ary[i])
                   ssOut << "  " << ary[i];
             return ssOut.str();
          }
    
    }; // class FillAryOddFirstClass2_t
    

    下面是main(),它说明了每个'fill'函数是如何使用的:

    int main()
    {
       const size_t sz = 9;
       {
          cout << "\n\n  Test1: original (function with static int pos)  \n";
    
          int ary[sz];       // automatic memory array
          init(&ary[0], sz); // function to fill ary with 0's
          show(&ary[0], sz);
    
          // this function uses static int pos
          fillAryOddFirst (&ary[0], sz);
          show(&ary[0], sz);
       }
    
       {
          cout << "\n\n  Test2: class wrapper (no static)\n";
    
          int ary[sz];
          init(&ary[0], sz);
          show(&ary[0], sz);
    
          {
             FillAryOddFirstClass_t faofObj;
             faofObj.fillAryOddFirst(&ary[0], sz);
          }
          show(&ary[0], sz);
       }
    
       {
          cout << "\n\n  Test3: Functor Wrapper (no static)\n";
    
          int ary[sz];  init(&ary[0], sz);
          show(&ary[0], sz);
    
          // no static int pos
          FillAryOddFirstFunctor_t()(&ary[0], sz);
          show(&ary[0], sz);
       }
    
       {
          cout << "\n\n  Test4: class, uses vector, not array (no static)\n";
    
          vector<int> iVec;
          for (uint i=0; i<sz; ++i) iVec.push_back(0); // vector grows
          show(&iVec[0], sz);
    
          {
             FillAryOddFirstClass_t faof;
             faof.fillAryOddFirst(&iVec[0], sz);
          }
          show(&iVec[0], sz);
       }
    
       {
          cout << "\n\n  Test5: class2 (no static) with graphic\n";
    
          vector<int> iVec;
          for (uint i=0; i<sz; ++i) iVec.push_back(0); // vector grows
          show(&iVec[0], sz);
    
          {
             cout << "\n    rlvl";
             FillAryOddFirstClass2_t faof2;
             faof2.fillAryOddFirst(1, &iVec[0], sz);
             cout << "\n    rlvl";
          }
          cout <<  "\n\n      ";
          show(&iVec[0], sz);
       }
    
       cout << endl;
       return 0;
    }
    

    输出:

      Test1: original (function with static int pos)  
         0  0  0  0  0  0  0  0  0
         9  7  5  3  1  2  4  6  8
    
    
      Test2: class wrapper (no static)
         0  0  0  0  0  0  0  0  0
         9  7  5  3  1  2  4  6  8
    
    
      Test3: Functor Wrapper (no static)
         0  0  0  0  0  0  0  0  0
         9  7  5  3  1  2  4  6  8
    
    
      Test4: class, uses vector, not array (no static)
         0  0  0  0  0  0  0  0  0
         9  7  5  3  1  2  4  6  8
    
    
      Test5: class2 (no static) with graphic
         0  0  0  0  0  0  0  0  0
    
        rlvl
         1     9 
         2     9 
         3     9  7 
         4     9  7 
         5     9  7  5 
         6     9  7  5 
         7     9  7  5  3 
         8     9  7  5  3 
         9     9  7  5  3  1 
    
               recurse end - decurse begins
    
         9     9  7  5  3  1_
         8     9  7  5  3  1_
         7     9  7  5  3  1  2_
         6     9  7  5  3  1  2_
         5     9  7  5  3  1  2  4_
         4     9  7  5  3  1  2  4_
         3     9  7  5  3  1  2  4  6_
         2     9  7  5  3  1  2  4  6_
         1     9  7  5  3  1  2  4  6  8_
        rlvl
    
               9  7  5  3  1  2  4  6  8
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-08
      • 2020-06-18
      • 2014-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多