В основном, просто думать о двух вещах:
- Может ли проблема быть выражена в той же (или аналогичной) проблеме, но с "более легкими" параметрами?
- Есть ли четкая точка, где эта более простая проблема становится тривиальной?
Вы обнаружите, что эти свойства верны для всех классических рекурсивных алгоритмов, таких как бинарный поиск, обход дерева, сортировка / слияние, факторные вычисления, вычисление наибольшего общего знаменателя и т. Д. (a) .
Если эти два условия выполнены, задача может быть пригодной для рекурсивного решения.
Я говорю «может», потому что даже проблемы, которые проявляют эти свойства, не всегда хорошо подходят для рекурсии, например:
// Add two unsigned inetegers.
unsigned int add (unsigned int a, unsigned int b) {
if (a == 0)
return b;
return add (a - 1, b + 1);
}
Теперь, хотя это несколько верное рекурсивное решение (хотя и немного надуманное), вам почти наверняка не хватит места в стеке, когда ваш начальный a
большой. Другими словами, реальный мир будет влиять на чистоту математической мысли.
(a) Вы можете задаться вопросом, почему существует разница между чем-то вроде add
выше и GCD или факториальными вычислениями. Ответ обычно заключается в том, насколько быстро «пространство поиска» (список всех возможных результатов) уменьшается с каждым рекурсивным вызовом.
Например, обход сбалансированного бинарного дерева исключит примерно половину оставшегося пространства поиска при каждом вызове. GCD-вычисления выполняют операцию модуля, которая также достаточно быстро сокращает пространство поиска.
Функция add
, однако, совсем не сокращает пространство поиска, поэтому она не подходит для рекурсии.
Факториал также не сокращает пространство поиска так быстро, поскольку он вычитает единицу из аргумента при каждом рекурсивном вызове (аналогично add
).
Однако люди все еще используют его, возможно потому, что вам не хватит места для факториала long , прежде чем количество рекурсивных вызовов изменится (64-разрядное целое число без знака будет содержать только около 20 !).