<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Поиск в глубину в JavaScript: DFS алгоритм с примерами кода]]></title><description><![CDATA[<p dir="auto">Поиск в глубину (DFS) - это базовый алгоритм для обхода графов и деревьев в JavaScript. Он помогает исследовать структуры данных, находя пути, циклы или компоненты связности.</p>
<p dir="auto">С DFS решают задачи вроде поиска маршрутов в лабиринтах, проверки циклов в графах или генерации деревьев. Алгоритм полезен в веб-разработке для анализа DOM-деревьев или сетевых структур. Если нужно быстро понять топологию графа без лишних проверок - DFS подойдет идеально.</p>
<h2>Как работает поиск в глубину</h2>
<p dir="auto">DFS начинает с выбранной вершины и уходит как можно глубже по одному пути, прежде чем вернуться назад. Это рекурсивный процесс: из текущей вершины вызывается DFS для каждого непосещенного соседа. Посещенные вершины помечаются, чтобы избежать циклов.</p>
<p dir="auto">Представь граф как лабиринт: DFS идет по коридору до тупика, затем возвращается и пробует другой. В отличие от поиска в ширину, он не гарантирует кратчайший путь, но эффективен для глубокого исследования. Сложность - O(V + E), где V - вершины, E - ребра. В JavaScript это реализуется через рекурсию или стек.</p>
<ul>
<li><strong>Рекурсивная основа</strong>: Функция dfs(v) отмечает v как посещенную, затем для каждого соседа вызывает dfs(сосед).</li>
<li><strong>Отслеживание состояний</strong>: Вершины бывают белые (непосещены), серые (в обработке), черные (обработаны) - это предотвращает зацикливание.</li>
<li><strong>Дерево обхода</strong>: Формируется из ребра, ведущих к новым вершинам; обратные ребра идут к предкам.</li>
</ul>
<h2>Реализация DFS в JavaScript</h2>
<p dir="auto">В JavaScript DFS легко написать рекурсивно для графов, представленных как объект с массивами соседей. Граф хранится в виде { ‘A’: [‘B’, ‘C’], ‘B’: [‘A’, ‘D’] }. Функция использует Set для visited, чтобы проверять посещенные узлы.</p>
<p dir="auto">Рекурсия удобна, но для больших графов может вызвать stack overflow - тогда нужен итеративный вариант со стеком. Пример: обход графа, выводящий порядок посещения. Это базовая реализация для ориентированного или неориентированного графа.</p>
<pre><code class="language-javascript">function dfs(graph, start, visited = new Set()) {
  if (visited.has(start)) return;
  visited.add(start);
  console.log(start);
  for (let neighbor of graph[start] || []) {
    dfs(graph, neighbor, visited);
  }
}
</code></pre>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Тип реализации</th>
<th>Преимущества</th>
<th>Недостатки</th>
<th>Когда использовать</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Рекурсивная</strong></td>
<td>Простой код, читаемость</td>
<td>Риск переполнения стека</td>
<td>Малые графы, деревья</td>
</tr>
<tr>
<td><strong>Итеративная (стек)</strong></td>
<td>Нет лимита рекурсии</td>
<td>Больше кода</td>
<td>Большие графы, production</td>
</tr>
<tr>
<td><strong>С колбэками</strong></td>
<td>Гибкость, enter/leave</td>
<td>Сложнее отлаживать</td>
<td>Кастомный обход</td>
</tr>
</tbody>
</table>
<ul>
<li><em>Рекурсивная</em>: Идеальна для обучения, работает как естественный “уйди вглубь”.</li>
<li><strong>Итеративная</strong>: Используй массив как стек - push для соседей, pop для обработки.</li>
<li><em>С состояниями</em>: Добавь tin/tout для времени входа/выхода - полезно для мостов или SCC.</li>
</ul>
<h2>Применение DFS в реальных задачах</h2>
<p dir="auto">DFS находит мосты в графе: ребро - мост, если удаление увеличивает компоненты. Запускаем DFS, вычисляем глубину h(u) и низшую точку f(u). Если f(v) &gt; h(u) для ребра u-v - это мост. В JS это решает задачи сетевой топологии или оптимизации.</p>
<p dir="auto">Еще DFS обнаруживает циклы: если сосед уже в обработке (серый), то цикл есть. Применяется в проверке DAG или раскраске графа. В веб-приложениях - для сериализации компонентов или поиска путей в React-дереве.</p>
<pre><code class="language-javascript">function findCycles(graph, start, visited = new Set(), recStack = new Set()) {
  visited.add(start);
  recStack.add(start);
  for (let neighbor of graph[start] || []) {
    if (!visited.has(neighbor)) {
      if (findCycles(graph, neighbor, visited, recStack)) return true;
    } else if (recStack.has(neighbor)) {
      return true; // Цикл!
    }
  }
  recStack.delete(start);
  return false;
}
</code></pre>
<ul>
<li><strong>Поиск мостов</strong>: Вычисляй min(f[v], h[предок]) для backtracking.</li>
<li><em>Циклы в графе</em>: Отслеживай recStack - серые вершины.</li>
<li><strong>Компоненты связности</strong>: Запускай DFS с каждой непосещенной вершины.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Задача</th>
<th>Почему DFS</th>
<th>Альтернатива</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Мосты/артикуляции</strong></td>
<td>Один проход O(n)</td>
<td>BFS медленнее</td>
</tr>
<tr>
<td>Обнаружение циклов</td>
<td>Простая рекурсия</td>
<td>Union-Find для unions</td>
</tr>
<tr>
<td><strong>Топосорт</strong></td>
<td>Линейный порядок</td>
<td>Kahn’s BFS</td>
</tr>
</tbody>
</table>
<h2>Вариации и оптимизации DFS</h2>
<p dir="auto">Для не связанных графов запускай DFS с каждой вершины - найдешь все компоненты. В дереве DFS строит эйлеров обход. Оптимизация: используй BitSet вместо Set для скорости на больших данных.</p>
<p dir="auto">В JS для DOM: window.document.createTreeWalker с фильтром - встроенный DFS. Для игр - генерация лабиринтов: рекурсивный backtracking. Подумай о таймерах для асинхронного DFS в браузере.</p>
<ul>
<li><strong>Асинхронный DFS</strong>: Используй async/await с очередью для UI не блокируй.</li>
<li><em>Bit manipulation</em>: Для sparse графов - биты вместо Set.</li>
<li><strong>С весами</strong>: Комбинируй с memoization для shortest path в DAG.</li>
</ul>
<p dir="auto"><strong>Когда DFS лучше BFS</strong>: Если память критична или нужен любой путь быстро. В лабиринтах - найдет выход, но не оптимальный.</p>
<h2>Ключевые метрики алгоритма</h2>
<p dir="auto">DFS создает <strong>дерево обхода</strong> с back-edges. Метрики tin/v - время входа/выхода помогают в анализе. Для мостов: f[u] = min(f[u], f[v]), проверка f[v] &gt; h[u].</p>
<p dir="auto">В коде отслеживай parent, чтобы различать tree/back edges. Это основа для Tarjan’s SCC или Kosaraju. Практика: реализуй на LeetCode (Number of Islands).</p>
<pre><code class="language-javascript">let time = 0;
function dfsWithTime(graph, u, parent, h, f, visited) {
  visited[u] = true;
  h[u] = time++;
  f[u] = h[u];
  for (let v of graph[u]) {
    if (v === parent) continue;
    if (!visited[v]) {
      dfsWithTime(graph, v, u, h, f, visited);
      f[u] = Math.min(f[u], f[v]);
    } else {
      f[u] = Math.min(f[u], h[v]);
    }
  }
}
</code></pre>
<h2>По ту сторону стека рекурсии</h2>
<p dir="auto">DFS хорош для глубоких структур, но рекурсия ограничена в Node.js (~10k вызовов). Итеративный вариант с while и стеком решает проблему. Остается вопрос: как масштабировать на миллионы вершин?</p>
<p dir="auto">Подумай о параллельном DFS или комбинации с BFS для hybrid поиска. В JS для больших данных смотри Web Workers. Это база, дальше - твои эксперименты с графами.</p>
]]></description><link>https://forum.exlends.ru/topic/866/poisk-v-glubinu-v-javascript-dfs-algoritm-s-primerami-koda</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:12:27 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/866.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 01 Mar 2026 06:48:02 GMT</pubDate><ttl>60</ttl></channel></rss>