8.3. Более сложные случаи рекурсии
Пусть функция
с натуральными аргументами и значениями
определена рекурсивно условиями
где
![a](/sites/default/files/tex_cache/0cc175b9c0f1b6a831c399e269772661.png)
- некоторое число, а
![h](/sites/default/files/tex_cache/2510c39011c5be704182423e3a695e91.png)
и
![l](/sites/default/files/tex_cache/2db95e8e1a9267b7a1188556b2013b33.png)
-
известные функции.
Другими словами,
значение функции ![f](/sites/default/files/tex_cache/8fa14cdd754f91cc6554c9e71929cce7.png)
в точке
![x](/sites/default/files/tex_cache/9dd4e461268c8034f5c8564e155c67a6.png)
выражается через
значение ![f](/sites/default/files/tex_cache/8fa14cdd754f91cc6554c9e71929cce7.png)
в точке
![l(x)](/sites/default/files/tex_cache/cbecedc4c06ce641160fae6c7922af1f.png)
. При этом
предполагается, что для любого
![x](/sites/default/files/tex_cache/9dd4e461268c8034f5c8564e155c67a6.png)
в последовательности
рано или поздно встретится
![0](/sites/default/files/tex_cache/cfcd208495d565ef66e7dff9f98764da.png)
.
Если дополнительно известно, что
для
всех
,
то вычисление
не представляет труда: вычисляем
последовательно ![f(0), f(1),\allowbreak f(2),\ldots](/sites/default/files/tex_cache/1734a3e937243f97ed16b55e683fca9a.png)
8.3.1.
Написать нерекурсивную программу вычисления
для общего
случая.
Решение. Для вычисления
вычисляем
последовательность
до появления нуля и запоминаем ее, а затем вычисляем
значения
![f](/sites/default/files/tex_cache/8fa14cdd754f91cc6554c9e71929cce7.png)
в точках этой последовательности, идя справа
налево.
Еще более сложный случай из следующей задачи вряд ли
встретится на практике (а если и встретится, то проще
рекурсию не устранять, а оставить). Но тем не менее: пусть
функция
с натуральными аргументами и значениями
определяется соотношениями
где
![a](/sites/default/files/tex_cache/0cc175b9c0f1b6a831c399e269772661.png)
- некоторое число, а
![l](/sites/default/files/tex_cache/2db95e8e1a9267b7a1188556b2013b33.png)
,
![r](/sites/default/files/tex_cache/4b43b0aee35624cd95b910189b3dc231.png)
и
![h](/sites/default/files/tex_cache/2510c39011c5be704182423e3a695e91.png)
- известные
функции. Предполагается, что если взять
произвольное число
и начать применять к нему функции
![l](/sites/default/files/tex_cache/2db95e8e1a9267b7a1188556b2013b33.png)
и
![r](/sites/default/files/tex_cache/4b43b0aee35624cd95b910189b3dc231.png)
в произвольном
порядке, то рано или поздно получится
![0](/sites/default/files/tex_cache/cfcd208495d565ef66e7dff9f98764da.png)
.
8.3.2.
Написать нерекурсивную программу вычисления
.
Решение. Можно было бы сначала построить дерево,
у которого в корне находится
, а в сыновьях
вершины
стоят
и
- если только
не
равно нулю.
Затем вычислять значения функции, идя от листьев к корню.
Однако есть и другой способ.
Обратной польской записью (или постфиксной записью )
выражения называют запись, где знак функции стоит после
всех ее аргументов, а скобки не используются. Вот несколько
примеров:
Постфиксная запись выражения позволяет удобно вычислять его
с помощью
![\emph{стекового калькулятора}](/sites/default/files/tex_cache/74c91cd769be847124d1e4eec10ee9f3.png)
.
Этот калькулятор имеет
стек, который мы будем представлять
себе расположенным горизонтально (числа вынимаются
и кладутся справа), и клавиши - числовые и функциональные.
При нажатии на клавишу с числом это число кладется в
стек.
При нажатии на функциональную клавишу соответствующая
функция применяется к нескольким аргументам у вершины
стека. Например, если в
стеке были числа
и нажата функциональная клавиша
![s](/sites/default/files/tex_cache/03c7c0ace395d80182db07ae2c30f034.png)
, соответствующая
функции от двух аргументов, то в
стеке окажутся числа
Перейдем теперь к нашей задаче. В процессе вычисления
значения функции
мы будем работать со стеком чисел,
а также с последовательностью чисел и символов f, l, r, h, которую мы будем интерпретировать как
последовательность нажатий клавиш на стековом калькуляторе.
Инвариант такой:
Пусть нам требуется вычислить
значение ![f(x)](/sites/default/files/tex_cache/50bbd36e1fd2333108437a2ca378be62.png)
. Тогда
вначале мы помещаем в
стек число
![x](/sites/default/files/tex_cache/9dd4e461268c8034f5c8564e155c67a6.png)
, а последовательность
содержит единственный символ
f. (При этом
инвариант
соблюдается.) Далее с последовательностью и
стеком
выполняются такие преобразования:
Здесь
![x](/sites/default/files/tex_cache/9dd4e461268c8034f5c8564e155c67a6.png)
,
![y](/sites/default/files/tex_cache/415290769594460e2e485922904f345d.png)
,
![z](/sites/default/files/tex_cache/fbade9e36a3f36d3d676c1b808451dd7.png)
- числа,
![X](/sites/default/files/tex_cache/02129bb861061d1a052c592e2dc6b383.png)
-
последовательность
чисел,
![P](/sites/default/files/tex_cache/44c29edb103a2872f519ad0c9a0fdaaa.png)
- последовательность чисел и символов
f,
l,
r,
h. В последней строке предполагается, что
![x\ne 0](/sites/default/files/tex_cache/2915aca00f796ab9165703b38b9b4e80.png)
. Эта строка соответствует равенству
Преобразования выполняются, пока последовательность не
станет пуста. В этот момент в
стеке окажется единственное
число, которое и будет ответом.
Замечание. Последовательность по существу представляет
собой стек отложенных заданий (вершина которого находится
слева).