web-dev-qa-db-fra.com

Utiliser la récursion pour additionner des nombres

Je viens juste d'étudier le concept de récursion et je pensais essayer un exemple simple. Dans le code suivant, j'essaie de prendre les nombres: 1, 2, 3, 4, 5 et de les additionner en utilisant la récursivité. Je m'attendais à 15, mais mon code en renvoie 16. 

Qu'est-ce que je fais mal?

Code:

    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

Vous retournez 1 dans la clause else. Vous devriez retourner 0:

else
{
    return 0;
}

Si la valeur n'est pas supérieure à zéro, pourquoi en renverriez-vous une en premier lieu?

35
Welbog

Votre code s'exécute comme suit:

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

Vérifiez votre cas de base.

17
mweiss

D'autres ont déjà noté l'erreur et je développerai sur la récursivité.

Bien que C # n'effectue pas actuellement l'optimisation de l'appel final (bien que IL ait une instruction tail spéciale), il convient de mentionner que la récursion de la fin est généralement une bonne chose. 

Tail récursion est un cas particulier de récursivité dans lequel la dernière opération de la fonction, l'appel de queue, est un appel récursif. Comme le dernier appel est l'appel récursif, il n'est pas nécessaire de conserver le cadre de pile de la fonction appelante et le compilateur peut facilement utiliser ces informations pour générer une instruction machine de sorte que la pile ne croisse pas du tout. Donc, il peut fondamentalement transformer une fonction récursive en une fonction itérative.

La réécriture de votre code pour prendre en charge la récursion de la queue peut être effectuée comme suit:

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

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

En effet, lorsque la valeur est = 0, vous retournez 1. Ensuite, il est ajouté.

La clause "else" de Sum devrait renvoyer 0.

5
Mario Marinato

Je préfère toujours mettre le (s) cas final (s) à l'avant pour qu'ils soient évidents, et j'ai une haine presque psychopathique violente des constructions "if cond then return a else return b". Mon choix serait (en précisant que cela ne fonctionnera pas correctement pour les nombres négatifs):

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

Je crois que c'est beaucoup plus lisible qu'un fouillis d'accolades et de flux de contrôle.

4
paxdiablo

Les autres ont déjà répondu à cette question, mais lorsque je travaille avec la récursivité, l’une des choses que j’aime faire pour vérifier que cela fonctionne est d’utiliser cocher le scénario de base et un scénario supplémentaire. Dans votre cas, je le testerais avec 1, ce qui donnerait 2. Étant donné que c'est manifestement faux, vous voudrez peut-être vérifier 0 qui n'utilisera aucune récursivité et il devrait donc être évident que l'erreur réside dans la classe de base.

En général, il est plus facile de raisonner sur la récursivité, car vous pouvez énumérer le nombre limité de choses à vérifier, mais elle nécessite au départ un acte de foi, car votre intuition sera fausse. Il suffit de tester les cas Edge et faire confiance aux maths il échouera jamais.

4
tomjen
int summation(int num){

    if (num==1)
        return 1;

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

Je suis presque sûr que le problème vient du fait que vous voulez que votre récursivité prenne fin lorsque value == 1 et se termine actuellement lorsque value == 0.

1
las3rjock

Votre expression terminale est en cause. Lorsque value == 0 (ou inférieur), il devrait renvoyer un 0 plutôt que 1. Par souci d'efficacité (admettons-le ici, ce n'est manifestement pas un problème, sinon la récursivité n'aurait pas été utilisée pour cette tâche) , vous devez terminer la récursion à la valeur == 1 et renvoyer un littéral 1 pour économiser un niveau inutile de récursivité.

1
Jason Musgrove

Pour commencer à la fin, une méthode Sum récursive ressemble à ceci:

    // 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; 

    }

Le codage en dur de startRange sur 0 nous donne:

    // 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;

    }

... et si vous voulez limiter la méthode aux nombres positifs, vous n'avez pas besoin de signe:

    // version 1

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

        }

        return range;

    }

J'espère que cela vous aidera à mieux comprendre la somme des tranches de nombres via la récursivité.

0

Cela pourrait aussi être écrit comme ceci:

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

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

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

En fait, je pense que vous n'avez pas besoin de vérifier le cas autrement parce que

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