Перейти к содержимому

27. Рекурсия

Иллюстрация к уроку Добро пожаловать в мир рекурсии! Рекурсия - мощный инструмент в программировании, позволяющий функции вызывать саму себя для решения более мелких подзадач. В этом уроке мы разберем эту концепцию на простых примерах.

Рекурсия - это техника программирования, когда функция вызывает саму себя внутри своего собственного тела. Представьте себе зеркало, отражающее другое зеркало - это бесконечный цикл отражений. В рекурсии важно иметь условие остановки, чтобы не уйти в бесконечный цикл, иначе программа просто зависнет. Это условие остановки называется базовый случай.

Давайте рассмотрим классический пример рекурсии - вычисление факториала числа. Факториал числа n (обозначается как n!) - это произведение всех целых чисел от 1 до n.

function factorial(n) {
// Базовый случай: факториал 0 равен 1
if (n === 0) {
return 1;
} else {
// Рекурсивный вызов: n! = n * (n-1)!
return n * factorial(n - 1);
}
}
console.log(factorial(5)); // Вывод: 120

В этом примере:

  • factorial(0) - это базовый случай. Когда n равно 0, функция возвращает 1 и рекурсия заканчивается.
  • return n * factorial(n - 1); - это рекурсивный вызов. Функция вызывает саму себя с аргументом n - 1.

Другой пример, демонстрирующий рекурсию:

function countdown(n) {
// Базовый случай: когда n меньше или равно 0, прекращаем отсчет
if (n <= 0) {
console.log("Пуск!");
} else {
console.log(n);
countdown(n - 1); // Рекурсивный вызов
}
}
countdown(5); // Вывод: 5 4 3 2 1 Пуск!

Рекурсия часто используется при работе с древовидными структурами данных, такими как DOM в веб-разработке. Например, если вам нужно найти все элементы определенного класса внутри элемента DOM и его потомков, рекурсивная функция может быть очень полезной.

Представьте, что вам нужно найти все элементы div с классом highlight в сложном HTML документе.

function findHighlightDivs(element) {
let highlights = [];
// Проверяем, является ли текущий элемент искомым
if (element.tagName === 'DIV' && element.classList.contains('highlight')) {
highlights.push(element);
}
// Перебираем дочерние элементы
for (let i = 0; i < element.children.length; i++) {
// Рекурсивно вызываем функцию для каждого дочернего элемента
highlights = highlights.concat(findHighlightDivs(element.children[i]));
}
return highlights;
}
// Пример использования:
const rootElement = document.getElementById('root'); // Предположим, что есть элемент с id "root"
const highlightedDivs = findHighlightDivs(rootElement);
console.log(highlightedDivs); // Выведет массив найденных элементов

Этот пример иллюстрирует, как рекурсия может быть использована для обхода дерева DOM. Фреймворки, такие как React и Vue.js, активно используют рекурсивные алгоритмы для обновления и рендеринга компонентов.

  • Базовый случай: Необходимо иметь условие остановки, чтобы рекурсия не стала бесконечной.
  • Рекурсивный вызов: Функция должна вызывать саму себя с измененными аргументами, приближаясь к базовому случаю.
  • Стек вызовов: Каждый рекурсивный вызов добавляется в стек вызовов. При слишком глубокой рекурсии может произойти переполнение стека (Stack Overflow).
  • Альтернативы: Рекурсию часто можно заменить итеративными решениями (циклами). Иногда итеративные решения более эффективны, особенно при работе с большими объемами данных.

Теперь вы знакомы с основами рекурсии! Попрактикуйтесь с различными примерами, чтобы лучше понять эту концепцию. Удачи!