web-dev-qa-db-ja.com

再帰を使用して数値を合計する

私は再帰の概念を研究してきたばかりで、簡単な例を試してみようと思いました。次のコードでは、1、2、3、4、5の数値を取得し、再帰を使用してそれらを追加しようとしています。結果は15になると予想していましたが、コードは16を返します。

何が悪いのですか?

コード:

    static void Main(string[] args)
    {

        Console.WriteLine(Sum(5));
        Console.Read();
    }


    static int Sum(int value)
    {
        if (value > 0)
        {
          return value + Sum(value - 1);
        }
        else
        {
            return 1;
        }
    }
13
Susan

Else句で1を返しています。あなたは0を返すはずです:

else
{
    return 0;
}

値がゼロ以下の場合、なぜ最初に1を返すのですか?

35
Welbog

コードは次のように実行されます。

Sum --> 5
  Sum --> 4
    Sum --> 3
      Sum --> 2
        Sum --> 1
          Sum --> 0
          1 <---
        2 <---
      4 <---
    7 <---
  11 <---
16 <---

ベースケースを確認してください。

18
mweiss

他の人はすでにエラーを指摘していたので、再帰について詳しく説明します。

現在、C#は末尾呼び出しの最適化を実行していません(ただし、ILには特別なtail命令があります)が、末尾再帰は一般的に良いことです。

Tail recursion は、関数の最後の操作であるtail呼び出しが再帰呼び出しである再帰の特殊なケースです。最後の呼び出しは再帰呼び出しであるため、呼び出し元の関数のスタックフレームを保持する必要はありません。コンパイラはこの情報を使用して、スタックがまったく成長しないように機械命令を簡単に生成できます。したがって、基本的に再帰関数を反復関数に変えることができます。

末尾再帰をサポートするようにコードを書き換えると、次のようになります。

static int Sum(int result, int value)
{
    if(value == 0)
        return result;

    return Sum(result + 1, value - 1);
}
14
Anton Gogolev
static int Sum(int value)
{
    if (value > 0)
    {
        return value + Sum(value - 1);
    }
    else
    {
        return 0; //Change this.
    }
}
7
Kirtan

これは、値が= 0の場合、1を返すためです。その後、追加されます。

Sumの「else」句は0を返します。

5
Mario Marinato

私は常に終了ケースを前に置くことを好み、それが明白になるようにします。また、私は"if cond then return a else return b"コンストラクト。私の選択は(負の数では正しく機能しないことを明確にする)でしょう:

static unsigned int Sum(unsigned int value) {
    if (value == 0)
        return 0;
    return value + Sum(value - 1);
}

私はそれが中括弧と制御フローの泥沼よりはるかに読みやすいと思います。

4
paxdiablo

他の人はすでにその質問に答えていますが、再帰を使用する場合、それが機能することを確認するために私がしたいことの1つは、基本ケースのチェックと1つの追加のケースを使用することです。私の場合、1でテストすると2になります。これは明らかに間違っているため、再帰を使用しない0を確認することをお勧めします。したがって、エラーが基本クラスにあることは明らかです。

一般に再帰は、チェックする必要があるものをリストすることができるので、推論するのが簡単ですが、直感が間違っているため、最初は信仰の飛躍が必要です。エッジのケースをテストするだけで数学を信頼してください失敗しますnever失敗します。

4
tomjen
int summation(int num){

    if (num==1)
        return 1;

    return summation(num-1)+num;
}
4
TAKxic

問題は、再帰をvalue == 1、およびvalue == 0

1
las3rjock

終了式が問題です。値== 0(またはそれ以下)の場合、1ではなく0を返す必要があります(効率を上げるために、ここで認めておきましょう。明らかに問題はありません。さもなければ、このタスクに再帰は使用されません) 、値== 1で再帰を終了し、リテラル1を返して、不要な再帰レベルを1つ保存する必要があります。

1
Jason Musgrove

最後に、再帰的なSumメソッドは次のようになります。

    // version 3

    public static int Sum(int startRange, int endRange)
    {
        if (endRange > startRange)
        {
            return endRange + Sum(startRange, endRange - 1);

        }

        if (endRange < startRange)
        {
            return startRange + Sum(endRange, startRange - 1);

        }

        return endRange; 

    }

StartRangeを0にハードコーディングすると、次のようになります。

    // version 2

    public static int Sum(int range)
    {
        if (range > 0)
        {
            return range + Sum(0, range - 1);

        }

        if (range < 0)
        {
            return Sum(range, -1);

        }

        return range;

    }

...そしてメソッドを正の数だけに制限したい場合は、記号は必要ありません:

    // version 1

    public static unsigned int Sum(unsigned int range)
    {
        if (range > 0)
        {
            return range + Sum(0, range - 1);

        }

        return range;

    }

これが、再帰を介して数値範囲を合計することへの洞察をより多く提供するのに役立つことを願っています。

0
WonderWorker

次のように書くこともできます。

public static int sum(int n){
    int total;

    if(n==1){
        total =1;

    }else{
        total = sum(n-1)+n;
    }
    return total;
}
0
ekeith

実際、他のケースをチェックする必要はないと思います。

public static int sum(int number){
    if(number > 0){
       return number + sum(--number);
    }
    return number; // return 0 so that's why you don't need check else condition
}
0
engineer
using System;
using NUnit.Framework;

namespace Recursion
{
  [TestFixture()]
    public class Test
    {
        [Test()]
        public void TestSum ()
        {
            Assert.AreEqual (Sum (new int[] { }), 0);
            Assert.AreEqual (Sum (new int[] { 0 }), 0);
            Assert.AreEqual (Sum (new int[] { 1 }), 1);
            Assert.AreEqual (Sum (new int[] { 1, 2, 3, 4, 5 }), 15);
        }

        public int Sum(int[] head)
        {
            if (head.Length == 0) return 0;

            int[] tail = new int[head.Length - 1];

            for (int i = 1; i < head.Length; i++) 
            {
                tail [i-1] = head [i];
            }

            return head[0] + Sum (tail);
        }
    }
}
0
superlogical