Прежде всего начнем с краткого, вероятно, неточного, но все же справедливого определения того, что такое переполнение стека.
Как вы, наверное, знаете, сейчас есть два разных типа памяти, которые реализованы в слишком разных структурах данных: кучи и стеки.
С точки зрения размера куча больше, чем стек, и, чтобы это было просто, предположим, что каждый раз при вызове функции в стек создается новая среда (локальные переменные, параметры и т. Д.). Поэтому, учитывая тот факт, что размер стека ограничен, если вы делаете слишком много вызовов функций, вы исчерпаете пространство, поэтому у вас будет переполнение стека.
Проблема с рекурсией заключается в том, что, поскольку вы создаете по меньшей мере одну среду в стеке на итерацию, вы очень быстро занимаете пространство в ограниченном стеке, поэтому переполнение стека обычно связано с вызовами рекурсии ,
Таким образом, эта функция называется оптимизацией вызовов рекурсии хвоста, которая будет повторно использовать одну и ту же среду при каждом вызове рекурсии, и поэтому пространство, занимаемое в стеке, является постоянным, что предотвращает проблему переполнения стека.
Теперь существуют некоторые правила для оптимизации оптимизации хвостовых вызовов. Во-первых, каждый вызов наиболее полно, и я имею в виду, что функция должна иметь возможность дать результат в любой момент, если вы прерываете выполнение, в SICP (http://mitpress.mit.edu/sicp/full-text/book/book.html) это называется итеративным процессом, даже если функция рекурсивна.
Если вы проанализируете свой первый пример, вы увидите, что каждая итерация определяется двумя рекурсивными вызовами, а это означает, что если вы прекратите выполнение в любое время, вы не сможете дать частичный результат, потому что результат зависит от тех вызовов, которые должны быть завершены, в этом случае вы не можете повторно использовать среду стека, потому что общая информация разделяется между всеми этими рекурсивными вызовами.
Однако второй пример не имеет этой проблемы, A является константой, а состояние p и r может быть определено локально, так как вся информация, которую следует продолжать, есть, тогда можно применить TCO.
Сложность, очевидно, различна. Говорит ли в ней что-нибудь об этом? –
это означает, что только второй алгоритм более эффективен, но не обязательно останавливает переполнение – happygilmore
, пожалуйста, проверьте мой ответ ниже. –