Не подходит для рекурсии.
. Несмотря на то, что незначительное исправление уже исправило вашу функцию, я хочу предположить, что эта версия показывает неправильное понимание рекурсии.
Ваша функция использует рекурсию для обновить то, что в противном случае было бы локальными переменными через некоторое время l oop. Это можно переписать так:
var reverse = function (s) {
var r = "";
var n = s.length - 1;
var i = 0;
if (n < 1) {
return s;
}
while (i <= n) {
r = r + s[n - i]
i++
}
return r
};
console .log (reverse ('abcde'))
Используемая вами рекурсия - это просто еще один способ написания того же кода.
Рекурсия предназначена для чего-то немного другого. Мы хотим, чтобы наши алгоритмы соответствовали нашим структурам данных. Чтобы рекурсия действительно имела смысл, мы должны использовать ее в рекурсивной структуре данных.
Но мы можем сделать это для этой проблемы.
Рекурсивно думать о строке
Часто существует много разных способов представить единую структуру данных. Мы можем представить строку как рекурсивную структуру следующим образом:
Строка может быть либо
- Пустая строка "", либо
- a символ, за которым следует строка
Мы можем назвать две части непустой строки head
и tail
.
Используя рекурсивное определение в рекурсивный алгоритм
С этой формулировкой мы можем написать рекурсивный алгоритм, который соответствует структуре:
Обращение строки либо
- обращение пустой строки (которая до сих пор является пустой строкой) или
- обращение хвоста, за которым следует голова
Затем код практически записывается сам:
const reverse = (string) =>
string .length == 0
? ""
: reverse (string .slice (1)) + string[0]
console .log (reverse ('abcdefg'))
Варианты
Конечно, возможны варианты этого. Мы могли бы быть готовы к тому, что оптимизация хвостового вызова, наконец, распространена в JS средах, и могла бы изменить ее на хвостовую рекурсивную версию, что-то вроде
const reverse = (string, result = "") =>
string .length == 0
? result
: reverse (string .slice (1), string [0] + result)
(обратите внимание, что существует потенциальная проблема с этим стилем. Параметры по умолчанию могут мешать использованию функции в определенных контекстах. Вы не можете, например, успешно вызвать strings .map (reverse)
с этой версией. Вы можете сделать это, разделив ее на вспомогательную функцию и основную функция, но это уводит нас в сторону.)
Или, воспользовавшись тем, что строки являются итеративными, мы могли бы написать довольно простую версию, используя деструктуризацию параметров вместе со значением по умолчанию:
const reverse = ([head = undefined, ...tail]) =>
head == undefined
? ""
: reverse (tail) + head
Преимущества рекурсии
И трудно представить, что становится намного проще, чем это. Эта версия фиксирует алгоритм довольно напрямую. И алгоритм четко привязан к нашему описанию структуры данных.
Обратите внимание на одну вещь, которую не использует ни одна из этих функций: локальные переменные . Простая рекурсия часто может быть написана таким образом, что в ней нет необходимости. Это большое благословение, потому что это означает, что изменчивому состоянию некуда спрятаться. А изменяемое состояние является источником множества ошибок программирования.