Практическая реализация
Решение реальных задач с помощью рекурсии
Типы задач, подходящие для рекурсии
graph TD
A[Области задач, подходящие для рекурсии] --> B[Обход дерева]
A --> C[Алгоритмы графов]
A --> D[Разделяй и властвуй]
A --> E[Обратный отслеживающий поиск]
Реализация рекурсивного обхода дерева
Обходы бинарного дерева в глубину
struct TreeNode {
int value;
struct TreeNode* left;
struct TreeNode* right;
};
// Обход в порядке инфиксной записи
void inorderTraversal(struct TreeNode* root) {
if (root == NULL) return;
inorderTraversal(root->left);
printf("%d ", root->value);
inorderTraversal(root->right);
}
Алгоритмы обхода графов
Поиск в глубину (DFS)
#define MAX_VERTICES 100
void dfs(int graph[MAX_VERTICES][MAX_VERTICES],
int vertices,
int start,
int visited[]) {
visited[start] = 1;
printf("%d ", start);
for (int i = 0; i < vertices; i++) {
if (graph[start][i] && !visited[i]) {
dfs(graph, vertices, i, visited);
}
}
}
Разделяй и властвуй: Сортировка слиянием
void merge(int arr[], int left, int mid, int right) {
int i, j, k;
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[left + i];
for (j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
i = 0; j = 0; k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++; k++;
}
while (j < n2) {
arr[k] = R[j];
j++; k++;
}
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
Обратный отслеживающий поиск: Задача N ферзей
#define N 8
int isSafe(int board[N][N], int row, int col) {
// Проверка строки и столбца
for (int i = 0; i < col; i++)
if (board[row][i]) return 0;
// Проверка главной диагонали
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--)
if (board[i][j]) return 0;
// Проверка побочной диагонали
for (int i = row, j = col; j >= 0 && i < N; i++, j--)
if (board[i][j]) return 0;
return 1;
}
int solveNQueens(int board[N][N], int col) {
if (col >= N) return 1;
for (int i = 0; i < N; i++) {
if (isSafe(board, i, col)) {
board[i][col] = 1;
if (solveNQueens(board, col + 1))
return 1;
board[i][col] = 0;
}
}
return 0;
}
Стратегии реализации рекурсии
| Стратегия |
Описание |
Сфера применения |
| Мемоизация |
Кэширование результатов |
Повторные подзадачи |
| Хвостовая рекурсия |
Оптимизация использования стека |
Линейные рекурсивные задачи |
| Преждевременная остановка |
Остановка при выполнении условия |
Алгоритмы поиска |
Обработка ошибок и ограничения
Распространённые ловушки при использовании рекурсии
- Переполнение стека
- Экспоненциальная сложность по времени
- Чрезмерное потребление памяти
Методы устранения
- Установка максимальной глубины рекурсии
- Использование итеративных альтернатив
- Реализация оптимизации хвостового вызова
Отладка рекурсивных алгоритмов
Стратегии отладки
- Использование операторов вывода
- Визуализация стека вызовов
- Пошаговое выполнение в отладчике
- Проверка базовых и рекурсивных случаев
LabEx рекомендует систематический подход к решению рекурсивных задач, делая упор на ясности логики и тщательной реализации.