Проблемы с текущим кодом
Есть две настоящие проблемы с вашей функцией. Во-первых, у вас есть куча недоступного кода:
function isPrime(...) {
if (...) {
return false
} else if (...) {
return true
} else {
return isPrime(...)
}
// Everything from here down cannot be reached. You already returned from this
// function in one branch or another in the block above.
}
Во-вторых, хотя вы правильно включаете базовые случаи, вы никогда не продвигаетесь к ним:
function isPrime(number, divisor) {
if (number == 1) { // Base case, testing on `number`
return false;
} else if (number == 2) { // Base case, testing on `number`
return true;
} else {
return isPrime(number, ++divisor); // Recursive case, doesn't change `number`
}
// Even if you could reach this section, it has the same problem.
}
Для рекурсии на работу вашрекурсивные случаи должны как-то прогрессировать в сторону базового случая. Прогрессирование может быть сложным, но если вы не можете продемонстрировать, что каждый последующий вызов как-то ближе к базовому случаю, то вы даже не знаете, может ли ваша программа завершиться, не говоря уже о ее правильности.
Почему стоит выбрать рекурсию?
Но у меня есть более фундаментальный вопрос. Почему вы хотите использовать рекурсию здесь? Это учебное упражнение для вас, домашнее задание или ваше личное обучение? Если так, это нормально. Это вполне законная проблема для изучения.
Но рекурсия и итерация одинаково эффективны. Довольно легко продемонстрировать, что все, что вы можете сделать с одним, вы можете сделать с другим. Поэтому выбор обычно сводится к тому, лучше ли ваша структура данных для рекурсии или итерации. Есть много структур, для которых рекурсия явно лучший выбор. Например, если вы обрабатываете древовидную структуру, рекурсия почти всегда будет чище и элегантнее. (Производительность - это отдельный вопрос, и речь пойдет о хвостовой рекурсии.) Если вы обрабатываете полный список элементов, рекурсия или итерация может быть лучше.
Но здесь проблема заключается в поискелюбые делители, останавливающиеся на первом. Вы можете сделать это с помощью простой итерации: делится на 2? , делится на 3? , делится на 4? , .. ., останавливаясь на первом да . Рекурсия не добавляет ничего, что делает это особенно чище.
(Обратите внимание, что одним из важных улучшений производительности является остановка, как только мы пропустим квадратный корень из нашего целевого значения, поскольку при наличии факторов один из них должен бытьменьше квадратного корня.)
Рекурсивное решение
Тем не менее, безусловно, может использовать рекурсию для реализации этого. Вот как я мог бы написать это:
const isPrime = (n, d = 2) =>
d * d > n
? true
: n % d == 0
? false
: isPrime (n, d + 1)
console .log (isPrime (40)) //=> false
console .log (isPrime (41)) //=> true
Или, в стиле вашего текущего кода,
function isPrime(n, d = 2) {
if (d * d > n) {
return true;
} else if (n % d == 0) {
return false;
} else {
return isPrime(n , d + 1)
}
}
И, в то время как мы могли бы также написать это как
const isPrime = (n, d = 2) =>
d * d > n || (n % d !== 0 && isPrime (n, d + 1))
Я думаю, это затрудняет понимание рекурсии.
Лучшая проблема для практики рекурсии
Наконец, если это разработано, чтобы помочь вам изучить рекурсию, позвольтеЯ предлагаю предложить связанную проблему, когда рекурсия более уместна. Напишите функцию, чтобы найти все основные факторы n
:
primeFactors(17) //=> [17]
primeFactors(18) //=> [2, 3, 3]
primeFactors(19) //=> [19]
primeFactors(20) //=> [2, 2, 5]
primeFactors(55440) //=> [2, 2, 2, 2, 3, 3, 5, 7, 11]
Опять же, это можно сделать итеративно или рекурсивно, но я думаю, что рекурсивные решения, вероятно, будут более приятным кодом.