Может кто-нибудь, пожалуйста, объяснить, как работает этот короткий код последовательности фибоначчи?

#python #python-3.x #recursion

#python #python-3.x #рекурсия

Вопрос:

Я понимаю рекурсию, я просто не понимаю, как работает этот код. Я пытался понять, печатая параметр x при каждом вызове функции.

 def fib(x):
  print(x)
  if x == 0 or x == 1:
    return 1
  else: 
    return fib(x-1)  fib(x-2)

print(fib(4))
  

Я получаю эти выходные данные:

 4
3
2
1
0
1
2
1
0
5
  

Но это просто не имеет смысла для меня.

Ответ №1:

Вот порядок выполнения рекурсии, синие прямоугольники обозначают каждый вызов функции, а красные — порядок. Обратите внимание, как красная линия проходит через поля в порядке вашей распечатки (начинается слева вверху и сначала перемещается влево вниз).

введите описание изображения здесь

Ответ №2:

Последовательность Фибоначчи — это разностное уравнение

f (x) = f (x-1) f (x-2), f(0)=f (1) = 1

Оператор if запрашивает, является ли ваше значение одним из значений серии по умолчанию, если это не так, то оно должно быть вычислено рекурсией, что выполняется в операторе else.

Что касается того, почему вы получаете этот запутанный вывод, то это потому, что функция fib () рекурсивно вызывает саму себя, суммируя каждый вызов.

В вашем примере это выглядит так

fib (4) выводит 4, затем вызывает fib (3) и fib (2), сначала он обращается к fib (3)

fib (3) выводит 3, затем вызывает fib (2) и fib (1), сначала он обращается к fib (2)

fib (2) выводит 2, затем вызывает fib (1) и fib (0), сначала он обращается к fib (1)

fib (1) выводит 1, затем возвращает 1

Теперь посещает fib (0), который выводит 0 и возвращает 1

Он поднимается на одну строку и посещает fib (1), который печатает 1 и возвращает 1

Затем он посещает fib (2), печатает 2 и вызывает fib (1) и fib (0), fib (1) печатает 1 и возвращает 1, fib (0) печатает 0 и возвращает 0

И вот ваш вывод. Последняя строка — это ответ

Ответ №3:

У него должна быть переменная ответа, равная номеру один номер два. Тогда номер один = номер два и номер два = ответ.

Комментарии:

1. что вы подразумеваете под переменной ответа

Ответ №4:

Возможно, добавление счетчика глубины помогло бы объяснить:

  def fib(x, depth=0):
     print('t' * depth   str(x))
     if x == 0 or x == 1:
             return 1
     else:
             return fib(x-1, depth 1)   fib(x-2, depth   1)
  

вывод для print(fib(4)) :

 4
        3
                2
                        1
                        0
                1
        2
                1
                0
5
  

Ответ №5:

По сути, то, что вы видите, — это внутренняя часть этой рекурсии для этого вывода и демонстрация языка программирования, оценивающего сложение слева направо. Вы можете подумать об этом алгоритме Фибоначчи следующим образом для fib(4) , если мы посмотрим на каждый вывод:

 4  - Call to fib(4)
3  - fib(4)'s call to fib(4-1)
2  - fib(4-1)'s call to fib(4-1-1)
1  - fib(4-1-1)'s call to fib(4-1-1-1): this returns a value of 1 because x = 1
0  - fib(4-1-1)'s call to fib(4-1-1-2): this returns 1 because x = 0; fib(4-1-1) returns 2 because the two 1s are added together
1  - fib(4-1)'s call to fib(4-1-2): this returns a value of 1 because x = 1; the 1 from this is added to the 2 from fib(4-1-1) to make the result for fib(4-1)
2  - fib(4)'s call to fib(4-2)
1  - fib(4-2)'s call to fib(4-2-1): this returns 1 because x = 1
0  - fib(4-2)'s call to fib(4-2-2): this returns 1 because x = 0; fib(4-2) returns 1 1 = 2; fib(4) returns 5 because fib(4-1) returned 3 and fib(4-2) returned 2
5  - Final result
  

Глядя на операции, всякий раз, когда мы добираемся до return fib(x-1) fib(x-2) инструкции, каждый раз fib(x-1) выполняется первым, потому что порядок операций слева направо, как при чтении.

На компьютерном уровне это расширяет операции примерно так, при этом каждая строка итеративно углубляется:

 fib(4)
fib(4-1)   fib(4-2)
(fib(3-1)   fib(3-2))   fib(4-2)
((fib(2-1)   fib(2-2))   fib(3-2))   fib(4-2)
((fib(1)   fib(0))   fib(3-2))   fib(4-2)
((1 1)   fib(3-2))   fib(4-2)
(2   fib(1))   fib(4-2)
(2 1)   fib(4-2)
3   fib(2)
3   (fib(2-1)   fib(2-2))
3   (fib(1)   fib(0))
3   (1   1)
3   2
5
  

Я сжал несколько частей из соображений экономии места, но, надеюсь, это должно донести суть.