Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.68/22: Рейтинг темы: голосов - 22, средняя оценка - 4.68
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53

Какова последовательность выполнения рекурсивной функции?

22.07.2013, 00:14. Показов 4652. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Хотел бы знать подробно, действия интерпретатора при обработке рекурсивной функции.
например, та же функция нахождения факториала:
Python
1
2
3
4
 def f(n):
... if n == 0:
... return 1
... return f(n-1)*n
Глядя, на эту функцию вообще не понятно как она работает. просто последовательно возвращает вызовы(никаких значений не возаращает), как все таки происходит вычисление?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.07.2013, 00:14
Ответы с готовыми решениями:

Дана последовательность. Составить програму с использованием рекурсивной функции
Дана последовательность. Составить програму с использованием рекурсивной функции

Разработать программу по алгоритму с использование рекурсивной функции и без использования рекурсивной функции
Разработать программу по алгоритму с использование рекурсивной функции и без использования рекурсивной функции.

Разработать программу согласно алгоритму с использованием рекурсивной функции и без использования рекурсивной
Разработать программу согласно алгоритму с использованием рекурсивной функции и без использования рекурсивной функции. n sinl ...

18
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
22.07.2013, 03:10
разбери по шагам для небольшого n
0
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
22.07.2013, 07:57  [ТС]
например, при n=4 последовательно возвращаются вызовы:
f(3)*2; f(2)*1, f(1). и как понимают вызов функции умноженный на число?
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
22.07.2013, 09:32
Code
1
2
3
f(4) превращается в f(3) * 4 -> f(3) превращается в f(2) * 3 -> f(2) превращается в f(1) * 2 -> f(1) превращается в f(0) * 1 -> f(0) превращается в 1
 
1 возвращается -> (1) * 1 возвращается -> (1 * 1) * 2 возвращается -> (1 * 1 * 2) * 3 возвращается -> (1 * 1 * 2 * 3) * 4 возвращается
Code
1
2
3
4
5
6
7
8
9
10
11
f(4) превращается в f(3) * 4
    f(3) превращается в f(2) * 3
        f(2) превращается в f(1) * 2
            f(1) превращается в f(0) * 1
                f(0) превращается в 1
 
1 возвращается
    (1) * 1 возвращается
        (1 * 1) * 2 возвращается
            (1 * 1 * 2) * 3 возвращается
                (1 * 1 * 2 * 3) * 4 возвращается
Добавлено через 3 минуты
Python
1
2
3
4
def f(n):
    if n < 2:
        return 1
    return f(n - 1) * n
0
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
22.07.2013, 09:32  [ТС]
А откуда операции умножения берутся? (1)*1, (1*1) *2,... По сути после возвращения f(0)*1, функция завершает работу
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
22.07.2013, 09:41
Цитата Сообщение от maks66 Посмотреть сообщение
По сути после возвращения f(0)*1, функция завершает работу
она завершает работу, но только не вся, а та копия, которая вызывалась
и возвращаемое значение передаётся в копию, которая вызывалась до неё
потом она завершается и и возвращаемое значение передаётся в копию, которая вызывалась до неё

первая копия - f(4)
вторая копия - f(3)
третья копия - f(2)
четвёртая копия - f(1)
пятая копия - f(0)
0
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
22.07.2013, 10:57  [ТС]
То есть я правильно понимаю: Когда запускается эта функция, сохраняются копии всех пяти вызовов, вычисление которых производится в конце после последнего вызова, а значения они получают от последнего, если f(0) = 1, то f(1) = 1*1, если f(1) = 1, f(2) = 1*2 и т.д.
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
22.07.2013, 12:15
Цитата Сообщение от maks66 Посмотреть сообщение
Когда запускается эта функция, сохраняются копии всех пяти вызовов
каждый вызов создаёт свой набор переменных, все наборы переменных одинаковые, но это независимые друг от друга наборы переменных
первый вызов не может завершиться, пока не завершиться второй вызов, вызванный из него
1
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
22.07.2013, 14:22
Функцию удобно мыслить как инструкцию, как руководство к действию. Задаём посчитать f(2). Функция говорит: это равно 2 * f(1), но сначала посчитать f(1). Как посчитать f(1)? Это 1 * f(0), а f(0) = 1. И возвращаемся. Таким образом, при выполнении рекурсии получается стек. В питоне глубина рекурсии ограничена и он принципиально не упрощает стек в случае хвостовой рекурсии.
1
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
22.07.2013, 17:25  [ТС]
Цитата Сообщение от accept Посмотреть сообщение
первый вызов не может завершиться, пока не завершиться второй вызов, вызванный из него
о чем это говорит? в момент последнего вызова все вызовы завершены, а обратное раскручивание рекурсии для нахождения результата это как я понял реализиция самой рекурсивной функции(т.е так происходит потому что так заложено в питоне)?
0
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
22.07.2013, 17:40
Да нет никакой разницы, рекурсия или нет. Пусть надо посчитать
cos 1 + sin sqrt 2
Как будет вычислять? Ему нужно вычислять сумму двух слагаемых. Но слагаемые сами ещё не вычислены. Поэтому сначала вычисляем слагаемые cos 1 и sin sqrt 2. Первое вычисляется сразу. Чтобы вычислить второе, нужно сначала вычислить sqrt 2. Это считается. Подставляем в синус. Подставляем синус и косинус в сумму. Получаем окончательный ответ. Всё это можно нарисовать деревом:
Code
1
2
3
4
5
6
7
 --+--
 |   |
cos sin
 |   |
 1  sqrt
     |
     2
1
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
22.07.2013, 21:55  [ТС]
если все вызовы завершили работу, почему все таки происходит обратное раскручивание вызовов для нахождения результата, значит так заложено в питоне?
0
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
22.07.2013, 22:45
Да как же они завершили работу? Смотрите в моём примере: чтобы посчитать +, нужно посчитать дерево для первого аргумента и дерево второго аргумента. А только потом завершается +. Рекурсия - то же самое, только иногда в дереве встречается та же самая функция:
Code
1
2
3
4
5
6
7
 f(2)
  |
2 * f(1)
     |
   1 * f(0)
        |
        1
Или две функции могут участвовать (взаимная рекурсия), или сколько угодно. Верхний вызов не закончится, пока не обойдётся всё дерево. Это общая природа вычисления выражений, питон не имеет никакой специфики (кроме ограничения вложенности рекурсии).
1
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
23.07.2013, 03:31
Цитата Сообщение от maks66 Посмотреть сообщение
в момент последнего вызова все вызовы завершены
наоборот, не завершены
последний вызов завершается и передаёт значение в предпоследний
предпоследний вызов завершается и передаёт значение в предпредпоследний

Добавлено через 20 секунд
Цитата Сообщение от maks66 Посмотреть сообщение
значит так заложено в питоне?
это во всех языках так
1
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
23.07.2013, 21:29  [ТС]
я попросил бы еще объяснить как происходит обход, рекурсивными вызовами, вложенных структур данных.
Python
1
2
3
4
5
6
7
8
9
def f(L):
y = 0
for x in L: 
if not isinstance(x, list):
y += x 
else:
y += f(x) 
return y
L=[1,[2,[3,4,5],6,[7,8]]
это ф-я суммирования вложенных стркутур даннных. Как происходит извлечение вложенных списков этой рек-й ф-ей для суммирования? здесь не видно ни условия выхода из рек-х вызовов, ни извлечения вложенных структур, получается и цикл for не работает, т.к при каждом вызове создается новое локальное пространство имен?
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
23.07.2013, 21:39
пиши с отступами, они являются аналогом фигурных скобок
0
0 / 0 / 0
Регистрация: 22.07.2013
Сообщений: 53
23.07.2013, 22:55  [ТС]
Python
1
2
3
4
5
6
7
8
9
10
def f(L):
    y = 0
    for x in L: 
        if not isinstance(x, list):
            y += x 
        else:
            y += f(x) 
    return y
 
L=[1,[2,[3,4,5],6,[7,8]]
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
23.07.2013, 23:18
Python
1
2
3
4
5
6
7
8
9
10
11
12
>>> def f(L):
...     y = 0
...     for x in L: 
...         if not isinstance(x, list):
...             y += x 
...         else:
...             y += f(x) 
...     return y
... 
>>> f([1, [2, [3, 4, 5], 6, [7, 8]]])
36
>>>
Цитата Сообщение от maks66 Посмотреть сообщение
здесь не видно ни условия выхода из рек-х вызовов
выход из каждого вызова происходит в строке с return

Цитата Сообщение от maks66 Посмотреть сообщение
ни извлечения вложенных структур
подсчёт суммы во вложенном списке происходит в строке с f(x)
после выполнения такого вызова возвращается число

Цитата Сообщение от maks66 Посмотреть сообщение
получается и цикл for не работает, т.к при каждом вызове создается новое локальное пространство имен?
при каждом вызове создаётся и новый набор переменных, и новый цикл по ним
в каждой копии свой цикл
1
4528 / 3522 / 358
Регистрация: 12.03.2013
Сообщений: 6,038
23.07.2013, 23:58
Цитата Сообщение от maks66 Посмотреть сообщение
Как происходит извлечение вложенных списков этой рек-й ф-ей для суммирования? здесь не видно ни условия выхода из рек-х вызовов, ни извлечения вложенных структур, получается и цикл for не работает, т.к при каждом вызове создается новое локальное пространство имен?
Чтобы найти сумму всех чисел, имеющихся в списке, нужно:
1. Сумму занулить.
2. Пройти по списку.
3. Если элемент - число, добавить его к сумме.
4. Если элемент - список, добавить к сумме сумму чисел, имеющихся в этом списке.

Инструкция абсолютно прозрачная, разве нет?

Может быть, вам было бы интересно почитать что-нибудь по функциональному программированию: лисп, хаскелл. По понятным причинам там рекурсии уделяется особое внимание.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.07.2013, 23:58
Помогаю со студенческими работами здесь

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

Доказать, что следующие функции удовлетворяют определению примитивно-рекурсивной функции
Доказать, что следующие функции удовлетворяют определению примитивно-рекурсивной функции (ПРФ): a) f(x, y, z)=(2x+3)y; б) f(x, y,...

С помощью рекурсивной функции вывести значение функции sin(x) от А до B включая с шагом step
Дан прототип функции void print_tab (float A, float B, float step) Как с помощью рекурсии вывести значение функции sin(x) от А до B...

Вычислить значение функции, разложив f(x) в ряд Тейлора. Разработать с использованием рекурсивной функции и без
Здравствуйте, помогите решить задание на рекурсию... Согласно варианту задания , вычислить значение функции в, разложив функцию f (x) в...

Два вызова рекурсивной функции в этой же функции
static void build (int a = 0, int b = 1, int c = 1, int d = 0, int level = 0) { if (level &lt; 3) { ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Новые блоги и статьи
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru