【问题标题】:Using recursion to add odd numbers使用递归添加奇数
【发布时间】:2009-08-15 23:45:23
【问题描述】:

我正在尝试编写一种方法来计算小于给定数字的所有数字中奇数的总和。所以例如。 CalcOdd(7) 将返回 5 + 3 + 1 = 9。CalcOdd (10) 将返回 9 + 7 + 5 + 3 + 1 = 25 等等

该方法需要输入一个数字,减去 1,然后递归地反向添加所有奇数,直到它达到 0。这就是我目前所拥有的。

    private static int CalcOdd(int n)
    {            

        if (n <= 1)
            return 1;
        else
            if (n % 2 == 0)
                n--;

        return n + CalcOdd(n - 2);
    }

它不太好用,它包括在加法中传入的数字,这不是我想要的。任何人都可以提出更好的方法吗?我还希望能够将答案移植到偶数,并添加选项以在答案中包含原始传入的数字。

非常感谢

【问题讨论】:

  • 家庭作业?如果是这样,请将其标记为这样
  • 对于谁反对这个,它有什么问题?问题很清楚,他们提供了示例代码,然后问出了什么问题。当然这可能是家庭作业,但它比“请给我密码”问题要好。

标签: c# recursion


【解决方案1】:

为什么要在这里使用递归?循环;或者更好的是,用一个简单的方程式计算出数学来做到这一点......

事实上,C# 不能为数学之类的东西提供出色的深度递归;尾声目前并不存在。

循环方法:

private static int CalcOdd(int n)
{
    int sum = 0, i = 1;
    while (i < n)
    {
        sum += i;
        i += 2;
    }
    return sum;
}

【讨论】:

  • "为什么要在这里使用递归?"也许他的教授希望他使用递归;)
  • 非常感谢 Marc,我意识到循环选项,但想使用递归来获得乐趣。它提供了一些递归挑战,因为它的条件(只有奇数)并且它需要在第一次传递时减去 1,但在随后的传递中不需要。
  • 为什么要使用递归而不是简单的数学公式?这对生产代码毫无意义,除非我遗漏了什么。
  • 哦,让我们用 LINQ-y 的优点来做吧:private static int CalcOdd(int n) { return (from x in Enumerable.Range(0,n) where (x &amp; 1) == 1 select x).Sum(); }
【解决方案2】:

如你所说,你可以用递归来做到这一点,但如果你想更快地做到这一点,那么我可以告诉你,前 n 个奇数之和等于 n*n。

private static int CalcOdd(int n) {
    if (n<=1)
        return 0;

    if (n%2 == 1)
        n--;

    int k = n/2;

    return k*k;
}

这样做的原因是:

每个偶数都是2k的形式,它之前的奇数是2k-1。

因为2*1-1 = 1,所以2k以下有k个奇数。

如果 n 是奇数,我们不想包含它,所以我们只需向下到它下面的偶数,我们就会自动得到我们想要的。

已编辑以修复损坏的代码。

【讨论】:

  • 啊,这将是数学位;-p 我已经开始使用 sum(1...n)=n(n+1)/2 的一张纸,但没有t完全走到了尽头;-p
  • 如果你看一下 1, 1+3, 1+3+5, ... ;)
  • -1 他没有要添加的奇数个数,他有一个开始,假设您调用 CalcOdd(9),您的函数将返回 9*9/4=20.25 (与 /4 有什么关系,它甚至不返回整数,如果您传入要添加的赔率数量,则将其排除在外会返回正确的结果)。 OP 希望它返回 7+5+3+1=16(或者如果您包括第一个数字)9+7+5+3+1=25。要计算出 0 和输入的值之间有多少个奇数,无论如何都需要一个递归函数(或一些真正的切割数学)
  • 当您记住每个其他数字都是奇数时,要添加的奇数个数是微不足道的。我已经修改了我的帖子以修复以前损坏的代码(但是精神保持不变)。还借此机会解释了它的工作原理并加以澄清。
  • 嗨塞巴斯蒂安,非常感谢您的回复。根据我对 Joshua 的 cmets - 请参阅我上面关于想要使用递归的评论,我也希望能够将其移植到即使没有,也可以选择在答案中包含或排除原始数字。即 calcodd(4) -> 4 + 3 + 1 或 calcodd(4) -> 3 + 1
【解决方案3】:

小于给定数的奇数之和是完美平方。

取(n/2)的整部分,得到比自身少的奇数个数。

平方,瞧!

private static int CalcSumOdd(int n)
{            
    int i;
    int.tryParse(n / 2, out i);
    return i*i;
}

对于偶数:

int i = n/2;
return i*(i+1);

修正。上述“偶数和”包括原数“n”。即 fn(12) = 42 = 2 + 4 + 6 + 8 + 10 + 12

如果你想排除它,你应该单方面排除它,或者根据传入的参数逻辑删除它。

【讨论】:

  • int i = n/2;?为什么使用TryParse
  • 获取“n”的一半的整个部分是一种笨拙的方法。也许有一种更有效的方法可以在 C# 中获取价值?
  • 那甚至无法编译。但是,请不要TryParse!你正在做整数除法,所以完全没有必要。
  • 嗨 Joshua,请参阅我上面关于想要使用递归的评论,我也希望能够将其移植到即使没有,也可以选择在回答。即 calcodd(4) -> 4 + 3 + 1 或 calcodd(4) -> 3 + 1
  • 使用 TryParse 甚至不起作用,因为您需要提供一个字符串作为第一个参数。对于整数 n / 2 已经为您提供了整数,对于其他所有内容,您可以使用 Math.Truncate()。
【解决方案4】:

这里是一个更正,

int CalcOdd(int n)
{ 
        n--; // <----

        if (n <= 1)
            return 0; // <----
        else
            if (n % 2 == 0)
                n--;

        return n + CalcOdd(n); // <----
}

【讨论】:

  • 已编辑以更正算法。返回 n + CalcOdd(n-1) 是不正确的,因为它跳过了序列中的数字,因为 n 已经递减了。
  • 尼克,非常感谢,但它不起作用。例如 CalcOdd(5) 在它应该是 4 (3 + 1) 时返回 5,如果你运行它 1 - 10。它到处都是错误的。但是非常感谢
  • Kieran,我的编辑应该返回有效数据。刚刚从 1 到 10 在这里测试过:1, 0; 2, 0; 3, 1; 4, 4; 5, 4; 6、9; 7、9; 8、16; 9、16; 10、25
【解决方案5】:

我是新来的,但这似乎是一个愚蠢的递归练习,因为它可以用一个简单的方程式来完成:

int sum(n,isEven,notFirst) {
    int c=1; //skip the else
    if (isEven) c=2;
    if (notFirst) n-=2;
    return ((n+c)*((n+c)/2))/2; }

经典离散数学和系列.. 从 1 到 100(奇数和偶数)的总和为 ((100+1)*(100/2))=5050

编辑:在我的代码中,如果您计算 n 为偶数的几率总和,反之亦然,它不起作用,但我不会将工作投入其中(并且放弃代码)现在。我假设你的代码会在它到达函数时处理这个问题。例如 7/2 不是 int (显然)

【讨论】:

    【解决方案6】:

    为什么要使用递归?

    private Int32 CalcOdd(Int32 value)
    {
        Int32 r = 0;
        {
            while (value >= 1)
            {
                value--;
                if (value % 2 != 0)
                {
                    r += value;
                }
            }               
        }
        return r;
    }
    

    【讨论】:

    • 嗨,非常感谢 - 我意识到我们可以使用循环选项,但想使用递归来获得乐趣。它提供了一些递归挑战,因为它的条件(只有奇数)并且它需要在第一次传递时减去 1,但在随后的传递中不需要。
    【解决方案7】:

    使用辅助函数。 CalcOdd 包括测试 n 以查看它是偶数还是奇数;如果是偶数,则返回 helper(n);如果是奇数,则返回 helper(n-2)。

    辅助函数必须处理三种情况: 1)n小于1;在这种情况下返回 0。 2) n 是偶数,在这种情况下返回 helper(n-1)。 3) n 为奇数,本例返回 n+helper(n-1)。

    【讨论】:

      【解决方案8】:
      public static int CalcOdd(int n) {
          // Find the highest even number. (Either n, or n-1.)
          // Divide that by 2, and the answer should be the square of that number.
          n = (n & 0x3FFFFFFE) >> 1;
          return (int)Math.Pow(n, 2);
      }
      

      【讨论】:

      • Math.Pow 是一种非常昂贵的整数平方方法,顺便说一句。返回 n * n;会很多便宜。
      【解决方案9】:
      
      private static int CalcOdd(int n) {
          n -= 1;
          if ((n & 1) == 0) n--;
          if (n <= 1) return 1;
          return n + CalcOdd(n - 1);
      }
      

      但我想说做循环更好更干净。

      
      private static int CalcOdd(int n) {
          int i, r = 1;
          for (i = 3; i < n; i+=2)
              r += i;
          return r;
      }
      

      【讨论】:

      • 您应该调用CalcOdd(n),因为您在函数调用开始时要减去一个。这个坏了。
      【解决方案10】:

      由于您想要包含或排除第一个答案的选项(并牢记您的“递归”约束):

      int calcOdd(int n, bool includeN)
      {
          if( !includeN )
              return calcOdd(n-1, true);
          if(n<=1)
              return 1;
          else
              if(n%2 == 0)
                  n--;
          return n+calcOdd(n-1, true);
      }
      

      includeFirst,如果作为 true 传递,将在计算中包含 n。否则,下一层将开始“包括N”。

      诚然,正如其他人所说,这是对递归的极其低效的使用,但是...如果您喜欢递归,请尝试 Haskell。它是一种几乎完全建立在概念之上的语言。

      【讨论】:

        【解决方案11】:
        int CalcOdd(int n)
        {            
            n -= 1;
        
            if (n <= 0)
                return 0; 
        
            if (n % 2 == 0)
                n--;
        
            return n + CalcOdd(n);
        }
        

        这个函数也是递归的,它有参数可以让你决定是做偶数还是奇数,以及是否要包含第一个数字。如果您对它的工作原理感到困惑,请记住 bool 也可以被视为 1(真)和 0(假)

        int Calc(int n, bool even = false, bool includeFirst = false)
        {           
            n -= !includeFirst;
        
            if (n <= 0)
                return 0; 
        
            if (n % 2 == even)
                n--;
        
            return n + Calc(n - includeFirst, even);
        }
        

        【讨论】:

        • 适用于奇数,现在让我们看看我是否可以将它移植到偶数并添加一个选项以包含初始数字。非常感谢
        • 删除“n -= 1”并将“return n + CalcOdd(n)”替换为“return n + CalcOdd(n - 1)”将包括初始数字。要执行偶数,请将“n % 2 == 0”更改为“n % 2 == 1”
        • 嗨,Håkon Evens 不工作。即传入 7 返回 15。如果我们只计算偶数,则答案应该始终是偶数。有什么想法吗?
        • 这可能是,用 c++ 做的,假设它足够相似。好吧,至少你明白了。
        【解决方案12】:

        Håkon,我已将您的代码移植到 VS 2008 中的 c#,如下所示

                static int Calc(int n, bool bEven, bool bIncludeFirst)
            {
                int iEven = Bool2Int(bEven);
                int iIncludeFirst = Bool2Int(bIncludeFirst);
        
                n -= 1 - iIncludeFirst;
        
                if (n <= 0)
                    return 0;
        
                if (n % 2 == iEven)
                    n--;
        
                return n + Calc(n - iIncludeFirst, bEven, bIncludeFirst);
            }
        
        
            private static int Bool2Int(bool b)
            {
                return b ? 1 : 0;
            }
        

        它似乎正在工作。现在有什么我可以做的吗?即我不想每次都将这些布尔值解析为整数等?

        【讨论】:

          【解决方案13】:

          我会将“使其奇数”部分与“每隔一个递减数字求和”部分隔离开来:(原谅 Python)

          def sumEveryTwoRecursive(n):
              if n <= 0:
                  return 0
              return n + sumEveryTwoRecursive(n - 2)
          
          def calcOdd(n):
              return sumEveryTwoRecursive(n - (2 if n % 2 else 1))
          

          【讨论】:

            【解决方案14】:

            因为这里还没有,所以我决定在这个钉子上使用 LINQ 锤子......

            (借自 Nick D 和 Jason 的配对编程答案here

            void Main()
            {
                GetIterator(7, true, false).Sum().Dump();
                // Returns 9
            
                GetIterator(10, true, false).Sum().Dump();
                // Returns 25
            }
            
            public IEnumerable<int> GetIterator(int n, bool isOdd, bool includeOriginal)
            {   
                if (includeOriginal)
                    n++;
            
                if (isOdd)
                    return GetIterator(n, 1);
                else
                    return GetIterator(n, 0);
            }
            
            public IEnumerable<int> GetIterator(int n, int odd)
            {
                n--;
            
                if (n < 0)
                    yield break;
            
                if (n % 2 == odd)
                    yield return n;
            
                foreach (int i in GetIterator(n, odd))
                    yield return i;
            }
            

            【讨论】:

              【解决方案15】:
              #include <iostream>
              
              using namespace std;
              
              int sumofodd(int num);
              
              int main()
              {
                  int number,res;
                  cin>>number;
                  res=sumofodd(number);
                  cout<<res;
                  return 0;
              }
              int sumofodd(int num)
              {    if(num<1) return 0;
                  if (num%2==0) num--;
                  return num+sumofodd(num-1);
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-05-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-11-21
                • 2016-05-31
                相关资源
                最近更新 更多