Двойной рекурсивный вызов

 def print_numbers(n, k):  
 """Print all numbers that (A) can be formed from the digits  of `n` in reverse
order and (B) are multiples of `k`.
  Args:  n (int): The number that results must use digits from. 
 k (int): The number that results must be multiples of.    
  >>> print_numbers(97531, 5) 
     135 
     15
     35"""
   def inner(n,s):
     if n == 0:
        if s % k == 0 and s > 0:
             print(s)
     else:
          inner(n // 10, s*10 + n % 10) #first
          inner(n // 10, s) #second
   inner(n,0)

У меня проблемы с пониманием части рекурсивных вызовов. Насколько я понимаю, второй рекурсивный вызов не может быть вызван до того, как первый достигнет фазы, когда он должен дать возвращаемое значение. Однако то, что делает первый вызов (в примере): он дает внутренний (9753,1), внутренний (975,13), внутренний (97,135), внутренний (9,1357), внутренний (0,13579)

Поскольку тогда n равно 0, s (13579) не делится на k (5), поэтому он ничего не печатает. Более того, по способу построения функции возвращаемое значение - None. Итак, когда достигается внутренняя (0,13579) фаза, второй рекурсивный вызов должен начать работать, однако он будет постоянно пытаться 0 // 10 и не будет продолжаться.

Это мое понимание. Вы можете указать, в чем я не прав?


person user13    schedule 03.12.2018    source источник


Ответы (1)


Пара вопросов. Во-первых, представьте себе рекурсию как иерархию стеков.

Однако то, что делает первый вызов (в примере): он дает внутренний (9753,1), внутренний (975,13), внутренний (97,135), внутренний (9,1357), внутренний (0,13579)

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

Итак, когда достигается внутренняя (0,13579) фаза, второй рекурсивный вызов должен начать работать, однако он будет постоянно пытаться 0 // 10 и не будет продолжаться.

Это ошибочно. Почему для этого вызова значение «n» должно быть нулевым? если вы помните, первый экземпляр этого вызова был во время блока else, который был выполнен для n = 97531.

Не имеет значения, что приведенный выше оператор перешел в рекурсию, потому что эти переменные и значения существуют в более низком стеке по сравнению со стеком, релевантным для этого оператора.

Более простой способ - рассматривать каждую стопку отдельно.

stack 1: n = 97531
else: #n//10 = 9753
    child1 (9753,1)
    child2 (9753,0)
            stack2 - child1:
            else: #n//10 = 975
                child11 (975,13)
                child12 (975,1)
            stack2 - child2:
            else: #n//10 = 975
                child21 (975, 3)
                child22 (975, 0) #and so on.

На каждом уровне иерархии определены свои переменные, и они будут порождать рекурсивные функции, принадлежащие более низкой иерархии, пока вы не достигнете базового случая отдельно для каждой «ветки / порождения», так сказать.

Подводя итоги. Все это можно свести к иерархии стопок. В этот момент эта функция становится простой для восприятия.
По сути, для каждой цифры, когда число больше нуля, выньте последнюю цифру и сделайте два выбора. Используйте последнюю цифру и отбросьте последнюю цифру. Делайте это снова и снова, и в конечном итоге вы будете рассматривать все возможные числа, которые можно сформировать в обратном порядке, используя или отбрасывая цифры.

person Paritosh Singh    schedule 03.12.2018