Во всех существующих решениях было слишком много кода, который на самом деле ничего не делал, поэтому вот мое мнение:
#include <iostream>
#include <string>
std::string
r(std::string s)
{
if (s.empty())
return s;
return r(s.substr(1)) + s[0];
}
int
main()
{
std::cout << r("testing") << std::endl;
}
P.S. Я наткнулся на этот вопрос, пытаясь найти способ C ++ для std::string
того, что s+1
для char *
в C; не пройдя весь маршрут s.substr(1, s.length()-1)
, который выглядит слишком некрасиво. Оказывается, есть std::string::npos
, что означает до конца строки, и это уже значение по умолчанию для второго аргумента, поэтому достаточно s.substr(1)
(плюс, он также выглядит более эффективным и наравне с простым s + 1
в С).
Обратите внимание, однако, что рекурсия в общем случае не масштабируется при увеличении входных данных, если только компилятор не может выполнить то, что известно как оптимизация хвостовой рекурсии. (На рекурсию редко обращаются в императивных языках.)
Однако, чтобы активировать оптимизацию хвостовой рекурсии, обычно требуется, чтобы (0) рекурсия происходила только внутри оператора return
и чтобы (1) никакие дальнейшие операции не выполнялись с результат рекурсивного обратного вызова в родительской функции.
Например, в приведенном выше случае + s[0]
логически выполняется родителем после завершения дочернего вызова (и, вероятно, будет так, даже если вы пойдете по более уродливому маршруту s[s.length()-1] +
), поэтому он может очень хорошо, чтобы большинство компиляторов не выполняли хвостовую рекурсию-оптимизацию, что делает функцию очень неэффективной на больших входах (если не нарушена из-за исчерпания кучи).
(Для чего я пытался написать более дружественное к хвосту рекурсивное решение (убедившись, что возвращаемый результат вырастет через аргумент самой функции), но разборка получающегося двоичного файла, кажется, предполагает, что это более сложный, чем в императивных языках, таких как C ++, см. gcc: нет ли хвостовой рекурсии, если я верну std :: string в C ++? .)