2016-05-06 2 views
0

Ответ, вероятно, ослепительно очевидный, но для жизни меня я не вижу. Я пытаюсь выяснить, сколько итераций требуется для того, чтобы положительное целое число, равное пользователю, сходилось к 1 (т. Е. Рекурсивная функция: f (x) = x/2, если x четный, 3x + 1, если x нечетный). Ответ тривиален, если выполняется грубая сила (т. Е. Через ряд утверждений if). Однако я стремился к рекурсивному подходу, и я застрял в бесконечном цикле:Рекурсия Collatz в бесконечном цикле C

#include <stdio.h> 

int collatz(long number, int length)  
{ 

    while (number != 1) 
    { 
     length++; 
     printf("%ld\n", number); 
     if ((number % 2) == 0) 
      collatz(number/2,length); 
     else 
      collatz(3*number+1,length); 
    } 

    return length; 
} 
int main() 
{ 
    long number; 
    printf("Input a number\n"); 
    scanf("%ld", &number); 
    int length=1; 
    printf("length is %d", collatz(number,length)); 
    return 0; 
} 

Проблема возникает, когда число = 1. Вместо завершения цикла он продолжается и поэтому колеблется между 1 и 2 бесконечно.

+3

Я чувствую, что это необходимо отметить, что это не хорошее использование рекурсии. У вас была правильная идея с циклом 'while'. Вместо рекурсивных вызовов просто обновите 'number', т. Е.' Number/= 2' и 'number = 3 * number + 1'. – user3386109

ответ

3

Заявление while (number != 1) никогда не будет оцениваться как ложное, поэтому вы застряли в бесконечном цикле всякий раз, когда вы проходите number != 1.

Что касается вычисления «длины», вы передаете значение, поэтому функция не будет вычислять количество итераций Collatz, необходимых для перехода к 1. Вместо этого просто верните один плюс число итераций Collatz для соответствующий преемник этого числа. Например, количество итераций Collatz, необходимых для числа n, равно 1, плюс номер, возвращаемый подходящим рекурсивным вызовом, либо на n/2, либо 3*n+1, в зависимости от того, является ли n четным или нечетным, соответственно.

Это будет работать:

int collatz(long number)  
{ 
    if (number != 1) 
    { 
     printf("%ld\n", number); 
     if ((number % 2) == 0) 
      return 1+collatz(number/2); 
     else 
      return 1+collatz(3*number+1); 
    } 

    return 0; 
} 
+0

Спасибо, я, наконец, получил его для работы с подходом, похожим на ваш. Я до сих пор не понимаю, почему я никогда не выхожу из цикла. Принимая вход = 8, например, сходится к 1 из 3 итераций, а gdb также показывает число = 1, но он не выйдет из цикла. – andreithegiant

+0

Вы не выходите из цикла, потому что переменная 'number' никогда не изменяется, потому что передача функции _copy_' number' в функцию. – blazs

+0

Gotcha, спасибо, хороший улов. – andreithegiant

0

I'm согласен с @blazs. Обратите внимание, что в цикле while вы фактически не изменяете номер переменной, поэтому, когда откат рекурсии к функции вызывающего абонента, цикл while снова оценит ЛОКАЛЬНУЮ копию числа переменных (которая не изменилась), а затем цикл while будет продолжать собираюсь навсегда ..

0

Это тоже работает, обходной путь к проблеме области видимости прохождения копии переменной функции:

#include <stdio.h> 

int collatz(long number, int length)  
{ 
    int temp=number;  
    int templength=length; 
    while (temp!= 1) 
    { 
     templength++; 
     printf("%ld\n", number); 
     if ((temp% 2) == 0) 
      return collatz(temp/2,templength); 
     else 
      return collatz(3*temp+1,templength); 
    } 

    return templength; 
} 
int main() 
{ 
    long number; 
    printf("Input a number\n"); 
    scanf("%ld", &number); 
    int length=1; 
    printf("length is %d", collatz(number,length)); 
    return 0; 
} 
Смежные вопросы