Ответ 1
Вы возвращаете 1 в предложении else. Вы должны возвращать 0:
else
{
return 0;
}
Если значение не больше нуля, почему вы должны вернуть его в первую очередь?
Я только что изучал концепцию рекурсии, и я подумал, что попробую простой пример. В следующем коде я пытаюсь взять числа: 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;
}
}
Вы возвращаете 1 в предложении else. Вы должны возвращать 0:
else
{
return 0;
}
Если значение не больше нуля, почему вы должны вернуть его в первую очередь?
Ваш код выполняется следующим образом:
Sum --> 5
Sum --> 4
Sum --> 3
Sum --> 2
Sum --> 1
Sum --> 0
1 <---
2 <---
4 <---
7 <---
11 <---
16 <---
Проверьте базовый футляр.
Другие уже заметили ошибку, и я расскажу о рекурсии.
Хотя С# в настоящее время не выполняет оптимизацию хвостовых вызовов (хотя IL имеет специальную инструкцию tail
), стоит упомянуть, что хвостовая рекурсия обычно хороша.
Рекурсия хвоста является частным случаем рекурсии, в которой последняя операция функции, хвостовой вызов, является рекурсивным вызовом. Поскольку последний вызов является рекурсивным вызовом, нет необходимости сохранять стек стека вызывающей функции, и компилятор может легко использовать эту информацию для генерации машинной команды, так что стек не растет вообще. Таким образом, он может в основном превратить рекурсивную функцию в итеративный.
Переписывание кода для поддержки рекурсии хвоста может быть выполнено следующим образом:
static int Sum(int result, int value)
{
if(value == 0)
return result;
return Sum(result + 1, value - 1);
}
static int Sum(int value)
{
if (value > 0)
{
return value + Sum(value - 1);
}
else
{
return 0; //Change this.
}
}
Это потому, что, когда значение равно = 0, вы возвращаете 1. Затем он добавляется.
Сумма "else" должна возвращать 0.
Я всегда предпочитаю положить завершающий регистр вперед, чтобы они были очевидны, и у меня есть жестокая почти психопатическая ненависть к конструкциям "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);
}
Я считаю, что это гораздо более читаемо, чем болото скобок и поток управления.
Другие уже ответили на этот вопрос, но когда я работаю с рекурсией, одна из вещей, которые мне нравится делать, чтобы проверить, что она работает, - это использовать базовый случай и один дополнительный случай. В вашем случае я проверил бы его с 1, что даст 2. Так как это, очевидно, неправильно, вы можете проверить на 0, который не собирается использовать какую-либо рекурсию, и поэтому должно быть очевидно, что ошибка лежит в базовом классе.
В целом рекурсия легче рассуждать, поскольку вы можете перечислить ограниченное количество вещей, которые вам нужно проверить, но изначально требуется скачок веры, поскольку ваша интуиция будет неправильной. Просто проверяйте случаи кросс и доверяйте математике, это никогда не потерпит неудачу.
int summation(int num){
if (num==1)
return 1;
return summation(num-1)+num;
}
Я уверен, проблема в том, что вы хотите, чтобы ваша рекурсия завершилась, когда value == 1
, и она в настоящее время завершается, когда value == 0
.
Ваше завершающее выражение не работает. Когда value == 0 (или ниже), оно должно возвращать 0, а не 1. Для эффективности (что, допустим, здесь, очевидно, не является проблемой, иначе рекурсия не была бы использована для этой задачи), вы должны завершить рекурсию со значением == 1 и вернуть литерал 1, чтобы сохранить один ненужный уровень рекурсии.
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);
}
}
}
Он также может быть записан следующим образом:
public static int sum(int n){
int total;
if(n==1){
total =1;
}else{
total = sum(n-1)+n;
}
return total;
}
На самом деле, я думаю, вам не нужно проверять дело иначе, потому что
public static int sum(int number){
if(number > 0){
return number + sum(--number);
}
return number; // return 0 so that why you don't need check else condition
}
Чтобы начать в конце, рекурсивный метод 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;
}
Надеюсь, что это поможет получить больше информации о суммировании диапазонов чисел через рекурсию.
Попробуйте этот код:
def sumr(n):
if n==0:
return n
return n+sumr(n-1)