This commit is contained in:
krahets
2026-03-30 08:17:41 +08:00
parent 68cafe99dd
commit 46bccf0065
484 changed files with 60193 additions and 20315 deletions
+58 -58
View File
@@ -65,8 +65,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
@@ -574,7 +574,7 @@
<span class="md-ellipsis">
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
@@ -596,7 +596,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
</label>
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 Что такое структуры данных и алгоритмы
1.2 Что такое алгоритм
@@ -1181,7 +1181,7 @@
<span class="md-ellipsis">
Глава 4. Массив и связный список
Глава 4. Массивы и списки
@@ -1203,7 +1203,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 4. Массив и связный список
Глава 4. Массивы и списки
</label>
@@ -1309,7 +1309,7 @@
<span class="md-ellipsis">
4.4 Память и кеш *
4.4 Оперативная память и кэш *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
Глава 6. Хеширование
Глава 6. Хеш-таблицы
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 6. Хеширование
Глава 6. Хеш-таблицы
</label>
@@ -1691,7 +1691,7 @@
<span class="md-ellipsis">
6.3 Хеш-алгоритмы
6.3 Алгоритмы хеширования
@@ -1786,7 +1786,7 @@
<span class="md-ellipsis">
Глава 7. Дерево
Глава 7. Деревья
@@ -1808,7 +1808,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 7. Дерево
Глава 7. Деревья
</label>
@@ -1886,7 +1886,7 @@
<span class="md-ellipsis">
7.3 Представление дерева массивом
7.3 Представление двоичного дерева массивом
@@ -1970,7 +1970,7 @@
<span class="md-ellipsis">
7.6 Резюме
7.6 Краткие итоги
@@ -2133,7 +2133,7 @@
<span class="md-ellipsis">
8.3 Задача Top-K
8.3 Задача Top-k
@@ -2226,7 +2226,7 @@
<span class="md-ellipsis">
Глава 9. Граф
Глава 9. Графы
@@ -2248,7 +2248,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 9. Граф
Глава 9. Графы
</label>
@@ -2407,7 +2407,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2463,7 +2463,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2602,7 +2602,7 @@
<span class="md-ellipsis">
10.2 Точка вставки двоичного поиска
10.2 Двоичный поиск точки вставки
@@ -2630,7 +2630,7 @@
<span class="md-ellipsis">
10.3 Граничные случаи двоичного поиска
10.3 Двоичный поиск границ
@@ -2658,7 +2658,7 @@
<span class="md-ellipsis">
10.4 Стратегия оптимизации через хеширование
10.4 Стратегии оптимизации хеширования
@@ -2686,7 +2686,7 @@
<span class="md-ellipsis">
10.5 Алгоритмы поиска: новый взгляд
10.5 Переосмысление алгоритмов поиска
@@ -2891,7 +2891,7 @@
<span class="md-ellipsis">
11.3 Пузырьковая сортировка
11.3 Сортировка пузырьком
@@ -2919,7 +2919,7 @@
<span class="md-ellipsis">
11.4 Сортировка вставкой
11.4 Сортировка вставками
@@ -3224,7 +3224,7 @@
<span class="md-ellipsis">
12.1 Алгоритмы разделяй и властвуй
12.1 Стратегия разделяй и властвуй
@@ -3252,7 +3252,7 @@
<span class="md-ellipsis">
12.2 Стратегия поиска разделяй и властвуй
12.2 Поисковая стратегия разделяй и властвуй
@@ -3529,7 +3529,7 @@
<span class="md-ellipsis">
13.4 Задача о $n$ ферзях
13.4 Задача о n ферзях
@@ -3670,7 +3670,7 @@
<span class="md-ellipsis">
14.1 Введение в динамическое программирование
14.1 Первое знакомство с динамическим программированием
@@ -3782,7 +3782,7 @@
<span class="md-ellipsis">
14.5 Задача о неограниченном рюкзаке
14.5 Задача о полном рюкзаке
@@ -4433,7 +4433,7 @@
<!-- Page content -->
<h1 id="91">9.1 &nbsp; Граф<a class="headerlink" href="#91" title="Permanent link">&para;</a></h1>
<p><u>Граф (graph)</u> - это нелинейная структура данных, состоящая из <u>вершин (vertex)</u> и <u>ребер (edge)</u>. Мы можем абстрактно представить граф <span class="arithmatex">\(G\)</span> как множество вершин <span class="arithmatex">\(V\)</span> и множество ребер <span class="arithmatex">\(E\)</span> . В примере ниже показан граф, содержащий 5 вершин и 7 ребер.</p>
<p><u>Граф (graph)</u> - это нелинейная структура данных, состоящая из <u>вершин (vertex)</u> и <u>ребер (edge)</u>. Граф <span class="arithmatex">\(G\)</span> можно абстрактно представить как множество вершин <span class="arithmatex">\(V\)</span> и множество ребер <span class="arithmatex">\(E\)</span> . Ниже приведен пример графа, содержащего 5 вершин и 7 ребер.</p>
<div class="arithmatex">\[
\begin{aligned}
V &amp; = \{ 1, 2, 3, 4, 5 \} \newline
@@ -4441,61 +4441,61 @@ E &amp; = \{ (1,2), (1,3), (1,5), (2,3), (2,4), (2,5), (4,5) \} \newline
G &amp; = \{ V, E \} \newline
\end{aligned}
\]</div>
<p>Если рассматривать вершины как узлы, а ребра как ссылки (указатели), соединяющие эти узлы, то граф можно считать структурой данных, выросшей из связного списка. Как показано на рисунке 9-1, <strong>по сравнению с линейными отношениями (связный список) и отношениями разделения (дерево), сетевые отношения (граф) обладают большей свободой</strong> , а потому и сложнее.</p>
<p>Если рассматривать вершины как узлы, а ребра как ссылки, соединяющие узлы, граф можно считать структурой данных, расширяющей связный список. Как показано на рисунке 9-1, <strong>по сравнению с линейными отношениями (связный список) и отношениями разделения (дерево), сетевые отношения (граф) обладают большей свободой</strong> и потому являются более сложными.</p>
<p><img alt="Связь между связным списком, деревом и графом" class="animation-figure" src="../graph.assets/linkedlist_tree_graph.png" /></p>
<p align="center"> Рисунок 9-1 &nbsp; Связь между связным списком, деревом и графом </p>
<h2 id="911">9.1.1 &nbsp; Распространенные типы и термины графов<a class="headerlink" href="#911" title="Permanent link">&para;</a></h2>
<p>В зависимости от того, имеют ли ребра направление, графы делятся на <u>неориентированные графы (undirected graph)</u> и <u>ориентированные графы (directed graph)</u> , как показано на рисунке 9-2.</p>
<p>В зависимости от наличия направления у ребер графы делятся на <u>неориентированные графы (undirected graph)</u> и <u>ориентированные графы (directed graph)</u> , как показано на рисунке 9-2.</p>
<ul>
<li>В неориентированном графе ребро означает "двустороннюю" связь между двумя вершинами, например отношение "друзья" в WeChat или QQ.</li>
<li>В ориентированном графе ребро имеет направление, то есть ребра <span class="arithmatex">\(A \rightarrow B\)</span> и <span class="arithmatex">\(A \leftarrow B\)</span> независимы друг от друга, как, например, отношения "подписка" и "подписчик" в Weibo или Douyin.</li>
<li>В неориентированном графе ребро представляет двустороннюю связь между двумя вершинами, например дружеские отношения в социальных сетях.</li>
<li>В ориентированном графе ребро имеет направление, то есть ребра <span class="arithmatex">\(A \rightarrow B\)</span> и <span class="arithmatex">\(A \leftarrow B\)</span> независимы друг от друга, например отношения подписки и подписчиков.</li>
</ul>
<p><img alt="Ориентированный и неориентированный графы" class="animation-figure" src="../graph.assets/directed_graph.png" /></p>
<p align="center"> Рисунок 9-2 &nbsp; Ориентированный и неориентированный графы </p>
<p>В зависимости от того, достижимы ли все вершины друг из друга, граф делится на <u>связный граф (connected graph)</u> и <u>несвязный граф (disconnected graph)</u> , как показано на рисунке 9-3.</p>
<p>В зависимости от того, связаны ли все вершины между собой, граф делится на <u>связный граф (connected graph)</u> и <u>несвязный граф (disconnected graph)</u> , как показано на рисунке 9-3.</p>
<ul>
<li>В связном графе, начиная из некоторой вершины, можно добраться до любой другой вершины.</li>
<li>В несвязном графе, начиная из некоторой вершины, по крайней мере одна вершина оказывается недостижимой.</li>
<li>В связном графе из любой вершины можно достичь любой другой вершины.</li>
<li>В несвязном графе существует по крайней мере одна вершина, недостижимая из текущей.</li>
</ul>
<p><img alt="Связный и несвязный графы" class="animation-figure" src="../graph.assets/connected_graph.png" /></p>
<p align="center"> Рисунок 9-3 &nbsp; Связный и несвязный графы </p>
<p>Мы также можем добавить к ребрам переменную "вес" и тем самым получить <u>взвешенный граф (weighted graph)</u> , показанный на рисунке 9-4. Например, в мобильных играх вроде Honor of Kings система может вычислять "степень близости" между игроками по времени, проведенному в совместных играх; такую сеть близости можно описать взвешенным графом.</p>
<p>Мы также можем добавить к ребрам переменную "вес" и получить показанный ниже <u>взвешенный граф (weighted graph)</u>. Например, в мобильных играх вроде Honor of Kings система рассчитывает "близость" между игроками по времени совместной игры, и такую сеть близости можно представить взвешенным графом.</p>
<p><img alt="Взвешенный и невзвешенный графы" class="animation-figure" src="../graph.assets/weighted_graph.png" /></p>
<p align="center"> Рисунок 9-4 &nbsp; Взвешенный и невзвешенный графы </p>
<p>Для структуры данных "граф" используются следующие распространенные термины.</p>
<p>Со структурой данных "граф" связаны следующие основные термины.</p>
<ul>
<li><u>Смежность (adjacency)</u>: если между двумя вершинами существует ребро, то эти вершины называются "смежными". На рисунке 9-4 вершинам 2, 3, 5 смежна вершина 1.</li>
<li><u>Путь (path)</u>: последовательность ребер, ведущая из вершины A в вершину B, называется "путем" от A до B. На рисунке 9-4 последовательность ребер 1-5-2-4 представляет один из путей от вершины 1 к вершине 4.</li>
<li><u>Степень (degree)</u>: число ребер, принадлежащих вершине. Для ориентированного графа <u>входящая степень (in-degree)</u> показывает число ребер, ведущих в вершину, а <u>исходящая степень (out-degree)</u> показывает число ребер, исходящих из вершины.</li>
<li><u>Смежность (adjacency)</u>: если между двумя вершинами существует ребро, то такие вершины называются смежными. На рисунке 9-4 с вершиной 1 смежны вершины 2, 3 и 5.</li>
<li><u>Путь (path)</u>: последовательность ребер от вершины A до вершины B называется путем из A в B. На рисунке 9-4 последовательность ребер 1-5-2-4 является одним из путей от вершины 1 к вершине 4.</li>
<li><u>Степень (degree)</u>: количество ребер, принадлежащих вершине. Для ориентированного графа <u>входящая степень (in-degree)</u> показывает, сколько ребер входит в вершину, а <u>исходящая степень (out-degree)</u> показывает, сколько ребер из нее выходит.</li>
</ul>
<h2 id="912">9.1.2 &nbsp; Представление графа<a class="headerlink" href="#912" title="Permanent link">&para;</a></h2>
<p>Распространенные способы представления графа включают "матрицу смежности" и "список смежности". Ниже в качестве примера используется неориентированный граф.</p>
<p>Распространенные способы представления графа включают "матрицу смежности" и "список смежности". Ниже для примера рассматривается неориентированный граф.</p>
<h3 id="1">1. &nbsp; Матрица смежности<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>Пусть число вершин графа равно <span class="arithmatex">\(n\)</span> ; тогда <u>матрица смежности (adjacency matrix)</u> использует матрицу размера <span class="arithmatex">\(n \times n\)</span> для представления графа: каждая строка и каждый столбец соответствуют вершине, а элементы матрицы отражают наличие ребра, то есть показывают, существует между двумя вершинами связь или нет.</p>
<p>Как показано на рисунке 9-5, пусть матрица смежности обозначается как <span class="arithmatex">\(M\)</span> , а список вершин - как <span class="arithmatex">\(V\)</span> ; тогда элемент матрицы <span class="arithmatex">\(M[i, j] = 1\)</span> означает, что между вершинами <span class="arithmatex">\(V[i]\)</span> и <span class="arithmatex">\(V[j]\)</span> существует ребро, а элемент <span class="arithmatex">\(M[i, j] = 0\)</span> означает, что ребра между ними нет.</p>
<p>Пусть число вершин графа равно <span class="arithmatex">\(n\)</span> ; тогда <u>матрица смежности (adjacency matrix)</u> использует матрицу размера <span class="arithmatex">\(n \times n\)</span> для представления графа, где каждая строка и каждый столбец соответствуют вершине, а элементы матрицы показывают наличие или отсутствие ребра.</p>
<p>Как показано на рисунке 9-5, обозначим матрицу смежности через <span class="arithmatex">\(M\)</span> , а список вершин через <span class="arithmatex">\(V\)</span> ; тогда элемент матрицы <span class="arithmatex">\(M[i, j] = 1\)</span> означает наличие ребра между вершинами <span class="arithmatex">\(V[i]\)</span> и <span class="arithmatex">\(V[j]\)</span> , а элемент <span class="arithmatex">\(M[i, j] = 0\)</span> означает отсутствие ребра.</p>
<p><img alt="Представление графа матрицей смежности" class="animation-figure" src="../graph.assets/adjacency_matrix.png" /></p>
<p align="center"> Рисунок 9-5 &nbsp; Представление графа матрицей смежности </p>
<p>Матрица смежности обладает следующими особенностями.</p>
<ul>
<li>В простом графе вершина не может соединяться сама с собой, поэтому элементы на главной диагонали матрицы смежности не имеют смысла.</li>
<li>Для неориентированного графа ребра в двух направлениях эквивалентны, поэтому матрица смежности симметрична относительно главной диагонали.</li>
<li>Если заменить в матрице смежности значения <span class="arithmatex">\(1\)</span> и <span class="arithmatex">\(0\)</span> на веса, то можно представить и взвешенный граф.</li>
<li>В простом графе вершина не может соединяться сама с собой, поэтому элементы на главной диагонали матрицы смежности не имеют значения.</li>
<li>Для неориентированного графа ребра в обоих направлениях эквивалентны, поэтому матрица смежности симметрична относительно главной диагонали.</li>
<li>Если заменить в матрице смежности значения <span class="arithmatex">\(1\)</span> и <span class="arithmatex">\(0\)</span> на веса, то можно представить взвешенный граф.</li>
</ul>
<p>При представлении графа матрицей смежности мы можем напрямую обращаться к элементам матрицы, чтобы получить информацию о ребрах, поэтому операции добавления, удаления, поиска и изменения обладают высокой эффективностью, равной <span class="arithmatex">\(O(1)\)</span> . Однако пространственная сложность матрицы равна <span class="arithmatex">\(O(n^2)\)</span> , поэтому она занимает заметный объем памяти.</p>
<p>При представлении графа матрицей смежности можно напрямую обращаться к элементам матрицы и получать сведения о ребрах, поэтому операции добавления, удаления, поиска и изменения обладают высокой эффективностью и выполняются за <span class="arithmatex">\(O(1)\)</span> . Однако пространственная сложность матрицы составляет <span class="arithmatex">\(O(n^2)\)</span> , поэтому она требует значительных затрат памяти.</p>
<h3 id="2">2. &nbsp; Список смежности<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p><u>Список смежности (adjacency list)</u> использует <span class="arithmatex">\(n\)</span> связанных списков для представления графа, где узлы списка обозначают вершины. <span class="arithmatex">\(i\)</span>-й список соответствует вершине <span class="arithmatex">\(i\)</span> и хранит все вершины, смежные с ней, то есть все вершины, соединенные с этой вершиной. На рисунке 9-6 показан пример графа, представленного списком смежности.</p>
<p><u>Список смежности (adjacency list)</u> использует <span class="arithmatex">\(n\)</span> списков для представления графа, где узлы списка обозначают вершины. <span class="arithmatex">\(i\)</span>-й список соответствует вершине <span class="arithmatex">\(i\)</span> и хранит все смежные с ней вершины, то есть все вершины, соединенные с данной вершиной. На рисунке 9-6 показан пример графа, представленного списком смежности.</p>
<p><img alt="Представление графа списком смежности" class="animation-figure" src="../graph.assets/adjacency_list.png" /></p>
<p align="center"> Рисунок 9-6 &nbsp; Представление графа списком смежности </p>
<p>Список смежности хранит только реально существующие ребра, а общее число ребер обычно значительно меньше <span class="arithmatex">\(n^2\)</span> , поэтому этот способ существенно экономит пространство. Однако для поиска ребра в списке смежности нужно проходить по списку, поэтому по времени он уступает матрице смежности.</p>
<p>Если посмотреть на рисунок 9-6, можно заметить, что <strong>структура списка смежности очень похожа на "метод цепочек" в хеш-таблице, поэтому для оптимизации эффективности здесь можно использовать сходные идеи</strong>. Например, когда список становится слишком длинным, его можно преобразовать в AVL-дерево или красно-черное дерево, чтобы улучшить временную сложность с <span class="arithmatex">\(O(n)\)</span> до <span class="arithmatex">\(O(\log n)\)</span> ; можно также превратить его в хеш-таблицу и снизить сложность до <span class="arithmatex">\(O(1)\)</span> .</p>
<p>Список смежности хранит только реально существующие ребра, а общее число ребер обычно значительно меньше <span class="arithmatex">\(n^2\)</span> , поэтому он лучше экономит память. Однако для поиска ребра в списке смежности требуется обходить список, поэтому по времени он уступает матрице смежности.</p>
<p>Если посмотреть на рисунок 9-6, можно заметить, что <strong>структура списка смежности очень похожа на цепную адресацию в хеш-таблицах, поэтому здесь можно использовать похожие методы оптимизации эффективности</strong>. Например, если список слишком длинный, его можно преобразовать в AVL-дерево или красно-черное дерево, чтобы снизить временную сложность с <span class="arithmatex">\(O(n)\)</span> до <span class="arithmatex">\(O(\log n)\)</span> ; также список можно преобразовать в хеш-таблицу, чтобы довести временную сложность до <span class="arithmatex">\(O(1)\)</span> .</p>
<h2 id="913">9.1.3 &nbsp; Типичные применения графов<a class="headerlink" href="#913" title="Permanent link">&para;</a></h2>
<p>Как показано в таблице 9-1, многие реальные системы можно моделировать графами, а соответствующие задачи затем сводить к задачам вычислений на графах.</p>
<p>Как показано в таблице 9-1, многие реальные системы можно моделировать с помощью графов, а соответствующие задачи затем сводить к задачам вычислений на графах.</p>
<p align="center"> Таблица 9-1 &nbsp; Распространенные графы в реальной жизни </p>
<div class="center-table">
@@ -4518,7 +4518,7 @@ G &amp; = \{ V, E \} \newline
<tr>
<td>Линии метро</td>
<td>Станция</td>
<td>Связность между станциями</td>
<td>Связь между станциями</td>
<td>Рекомендация кратчайшего маршрута</td>
</tr>
<tr>
@@ -4576,7 +4576,7 @@ aria-label="Нижний колонтитул"
<a
href="../graph_operations/"
class="md-footer__link md-footer__link--next"
aria-label="Вперед: 9.2 Базовые операции над графами"
aria-label="Вперед: 9.2 Базовые операции графа"
rel="next"
>
<div class="md-footer__title">
@@ -4584,7 +4584,7 @@ aria-label="Нижний колонтитул"
Вперед
</span>
<div class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
</div>
</div>
<div class="md-footer__button md-icon">
+42 -42
View File
@@ -65,8 +65,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
@@ -574,7 +574,7 @@
<span class="md-ellipsis">
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
@@ -596,7 +596,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
</label>
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 Что такое структуры данных и алгоритмы
1.2 Что такое алгоритм
@@ -1181,7 +1181,7 @@
<span class="md-ellipsis">
Глава 4. Массив и связный список
Глава 4. Массивы и списки
@@ -1203,7 +1203,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 4. Массив и связный список
Глава 4. Массивы и списки
</label>
@@ -1309,7 +1309,7 @@
<span class="md-ellipsis">
4.4 Память и кеш *
4.4 Оперативная память и кэш *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
Глава 6. Хеширование
Глава 6. Хеш-таблицы
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 6. Хеширование
Глава 6. Хеш-таблицы
</label>
@@ -1691,7 +1691,7 @@
<span class="md-ellipsis">
6.3 Хеш-алгоритмы
6.3 Алгоритмы хеширования
@@ -1786,7 +1786,7 @@
<span class="md-ellipsis">
Глава 7. Дерево
Глава 7. Деревья
@@ -1808,7 +1808,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 7. Дерево
Глава 7. Деревья
</label>
@@ -1886,7 +1886,7 @@
<span class="md-ellipsis">
7.3 Представление дерева массивом
7.3 Представление двоичного дерева массивом
@@ -1970,7 +1970,7 @@
<span class="md-ellipsis">
7.6 Резюме
7.6 Краткие итоги
@@ -2133,7 +2133,7 @@
<span class="md-ellipsis">
8.3 Задача Top-K
8.3 Задача Top-k
@@ -2226,7 +2226,7 @@
<span class="md-ellipsis">
Глава 9. Граф
Глава 9. Графы
@@ -2248,7 +2248,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 9. Граф
Глава 9. Графы
</label>
@@ -2307,7 +2307,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2325,7 +2325,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2435,7 +2435,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2574,7 +2574,7 @@
<span class="md-ellipsis">
10.2 Точка вставки двоичного поиска
10.2 Двоичный поиск точки вставки
@@ -2602,7 +2602,7 @@
<span class="md-ellipsis">
10.3 Граничные случаи двоичного поиска
10.3 Двоичный поиск границ
@@ -2630,7 +2630,7 @@
<span class="md-ellipsis">
10.4 Стратегия оптимизации через хеширование
10.4 Стратегии оптимизации хеширования
@@ -2658,7 +2658,7 @@
<span class="md-ellipsis">
10.5 Алгоритмы поиска: новый взгляд
10.5 Переосмысление алгоритмов поиска
@@ -2863,7 +2863,7 @@
<span class="md-ellipsis">
11.3 Пузырьковая сортировка
11.3 Сортировка пузырьком
@@ -2891,7 +2891,7 @@
<span class="md-ellipsis">
11.4 Сортировка вставкой
11.4 Сортировка вставками
@@ -3196,7 +3196,7 @@
<span class="md-ellipsis">
12.1 Алгоритмы разделяй и властвуй
12.1 Стратегия разделяй и властвуй
@@ -3224,7 +3224,7 @@
<span class="md-ellipsis">
12.2 Стратегия поиска разделяй и властвуй
12.2 Поисковая стратегия разделяй и властвуй
@@ -3501,7 +3501,7 @@
<span class="md-ellipsis">
13.4 Задача о $n$ ферзях
13.4 Задача о n ферзях
@@ -3642,7 +3642,7 @@
<span class="md-ellipsis">
14.1 Введение в динамическое программирование
14.1 Первое знакомство с динамическим программированием
@@ -3754,7 +3754,7 @@
<span class="md-ellipsis">
14.5 Задача о неограниченном рюкзаке
14.5 Задача о полном рюкзаке
@@ -4377,13 +4377,13 @@
<!-- Page content -->
<h1 id="92">9.2 &nbsp; Базовые операции графа<a class="headerlink" href="#92" title="Permanent link">&para;</a></h1>
<p>Базовые операции графа можно разделить на операции над "ребрами" и операции над "вершинами". В двух способах представления - "матрица смежности" и "список смежности" - реализация будет различаться.</p>
<p>Базовые операции графа можно разделить на операции над "ребрами" и операции над "вершинами". При двух способах представления, "матрице смежности" и "списке смежности", реализация этих операций различается.</p>
<h2 id="921">9.2.1 &nbsp; Реализация на основе матрицы смежности<a class="headerlink" href="#921" title="Permanent link">&para;</a></h2>
<p>Пусть дан неориентированный граф с числом вершин <span class="arithmatex">\(n\)</span> . Тогда способы реализации различных операций показаны на рисунках ниже.</p>
<ul>
<li><strong>Добавление или удаление ребра</strong>: достаточно изменить соответствующее ребро в матрице смежности, это требует <span class="arithmatex">\(O(1)\)</span> времени. Поскольку граф неориентированный, нужно одновременно обновлять ребра в обоих направлениях.</li>
<li><strong>Добавление вершины</strong>: в конец матрицы смежности добавляется одна строка и один столбец, которые полностью заполняются нулями; это требует <span class="arithmatex">\(O(n)\)</span> времени.</li>
<li><strong>Удаление вершины</strong>: из матрицы смежности удаляется одна строка и один столбец. В худшем случае, когда удаляются первая строка и первый столбец, приходится "сдвигать вверх-влево" <span class="arithmatex">\((n-1)^2\)</span> элементов, поэтому требуется <span class="arithmatex">\(O(n^2)\)</span> времени.</li>
<li><strong>Добавление или удаление ребра</strong>: достаточно изменить соответствующее ребро в матрице смежности, что требует <span class="arithmatex">\(O(1)\)</span> времени. Поскольку граф неориентированный, необходимо одновременно обновить ребра в обоих направлениях.</li>
<li><strong>Добавление вершины</strong>: в конец матрицы смежности добавляется строка и столбец, полностью заполненные нулями; это требует <span class="arithmatex">\(O(n)\)</span> времени.</li>
<li><strong>Удаление вершины</strong>: из матрицы смежности удаляется строка и столбец. При удалении первой строки и первого столбца достигается худший случай, когда требуется "сдвинуть влево вверх" <span class="arithmatex">\((n-1)^2\)</span> элементов, поэтому используется <span class="arithmatex">\(O(n^2)\)</span> времени.</li>
<li><strong>Инициализация</strong>: передаются <span class="arithmatex">\(n\)</span> вершин, затем инициализируется список вершин <code>vertices</code> длины <span class="arithmatex">\(n\)</span> , что требует <span class="arithmatex">\(O(n)\)</span> времени; после этого инициализируется матрица смежности <code>adjMat</code> размера <span class="arithmatex">\(n \times n\)</span> , что требует <span class="arithmatex">\(O(n^2)\)</span> времени.</li>
</ul>
<div class="tabbed-set tabbed-alternate" data-tabs="1:5"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Инициализация матрицы смежности</label><label for="__tabbed_1_2">Добавление ребра</label><label for="__tabbed_1_3">Удаление ребра</label><label for="__tabbed_1_4">Добавление вершины</label><label for="__tabbed_1_5">Удаление вершины</label></div>
@@ -5566,8 +5566,8 @@
<h2 id="922">9.2.2 &nbsp; Реализация на основе списка смежности<a class="headerlink" href="#922" title="Permanent link">&para;</a></h2>
<p>Пусть неориентированный граф содержит в сумме <span class="arithmatex">\(n\)</span> вершин и <span class="arithmatex">\(m\)</span> ребер. Тогда различные операции можно реализовать способом, показанным на рисунках ниже.</p>
<ul>
<li><strong>Добавление ребра</strong>: достаточно добавить ребро в конец списка, соответствующего вершине; это требует <span class="arithmatex">\(O(1)\)</span> времени. Поскольку граф неориентированный, нужно одновременно добавлять ребра в обоих направлениях.</li>
<li><strong>Удаление ребра</strong>: нужно найти и удалить указанное ребро в списке, соответствующем вершине; это требует <span class="arithmatex">\(O(m)\)</span> времени. В неориентированном графе нужно удалять ребра в обоих направлениях.</li>
<li><strong>Добавление ребра</strong>: достаточно добавить ребро в конец списка, соответствующего вершине; это требует <span class="arithmatex">\(O(1)\)</span> времени. Поскольку граф неориентированный, необходимо одновременно добавить ребра в обоих направлениях.</li>
<li><strong>Удаление ребра</strong>: нужно найти и удалить указанное ребро в списке, соответствующем вершине; это требует <span class="arithmatex">\(O(m)\)</span> времени. В неориентированном графе необходимо удалить ребра в обоих направлениях.</li>
<li><strong>Добавление вершины</strong>: в список смежности добавляется еще один список, а новая вершина становится его головным узлом; это требует <span class="arithmatex">\(O(1)\)</span> времени.</li>
<li><strong>Удаление вершины</strong>: требуется пройти по всему списку смежности и удалить все ребра, содержащие указанную вершину; это требует <span class="arithmatex">\(O(n + m)\)</span> времени.</li>
<li><strong>Инициализация</strong>: в списке смежности создаются <span class="arithmatex">\(n\)</span> вершин и <span class="arithmatex">\(2m\)</span> ребер; это требует <span class="arithmatex">\(O(n + m)\)</span> времени.</li>
@@ -5595,10 +5595,10 @@
<p>Ниже приведен код списка смежности. По сравнению с рисунками выше, реальная реализация имеет следующие отличия.</p>
<ul>
<li>Чтобы упростить добавление и удаление вершин, а также упростить код, мы используем список, то есть динамический массив, вместо связного списка.</li>
<li>Чтобы упростить добавление и удаление вершин, а также сделать код проще, мы используем список, то есть динамический массив, вместо связного списка.</li>
<li>Для хранения списка смежности используется хеш-таблица, где <code>key</code> - это экземпляр вершины, а <code>value</code> - список смежных вершин данной вершины.</li>
</ul>
<p>Кроме того, в списке смежности мы используем класс <code>Vertex</code> для представления вершины. Причина в следующем: если, как и в матрице смежности, различать вершины по индексам списка, то при удалении вершины с индексом <span class="arithmatex">\(i\)</span> пришлось бы обходить весь список смежности и уменьшать на <span class="arithmatex">\(1\)</span> все индексы, большие <span class="arithmatex">\(i\)</span> , что крайне неэффективно. Если же каждая вершина является уникальным экземпляром <code>Vertex</code> , то после удаления одной вершины остальные вершины менять уже не требуется.</p>
<p>Кроме того, в списке смежности используется класс <code>Vertex</code> для представления вершины. Причина в том, что если, как и в матрице смежности, различать вершины по индексам списка, то при удалении вершины с индексом <span class="arithmatex">\(i\)</span> пришлось бы обходить весь список смежности и уменьшать на <span class="arithmatex">\(1\)</span> все индексы, большие <span class="arithmatex">\(i\)</span> , что крайне неэффективно. Если же каждая вершина является уникальным экземпляром <code>Vertex</code> , то после удаления одной вершины остальные вершины менять уже не требуется.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:13"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><input id="__tabbed_4_10" name="__tabbed_4" type="radio" /><input id="__tabbed_4_11" name="__tabbed_4" type="radio" /><input id="__tabbed_4_12" name="__tabbed_4" type="radio" /><input id="__tabbed_4_13" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">Python</label><label for="__tabbed_4_2">C++</label><label for="__tabbed_4_3">Java</label><label for="__tabbed_4_4">C#</label><label for="__tabbed_4_5">Go</label><label for="__tabbed_4_6">Swift</label><label for="__tabbed_4_7">JS</label><label for="__tabbed_4_8">TS</label><label for="__tabbed_4_9">Dart</label><label for="__tabbed_4_10">Rust</label><label for="__tabbed_4_11">C</label><label for="__tabbed_4_12">Kotlin</label><label for="__tabbed_4_13">Ruby</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -6702,7 +6702,7 @@
<div style="margin-top: 5px;"><a href="https://pythontutor.com/iframe-embed.html#code=class%20Vertex%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20val%3A%20int%29%3A%0A%20%20%20%20%20%20%20%20self.val%20%3D%20val%0A%0Adef%20vals_to_vets%28vals%3A%20list%5Bint%5D%29%20-%3E%20list%5B%27Vertex%27%5D%3A%0A%20%20%20%20return%20%5BVertex%28val%29%20for%20val%20in%20vals%5D%0A%0Aclass%20GraphAdjList%3A%0A%0A%20%20%20%20def%20__init__%28self%2C%20edges%3A%20list%5Blist%5BVertex%5D%5D%29%3A%0A%20%20%20%20%20%20%20%20self.adj_list%20%3D%20dict%5BVertex%2C%20list%5BVertex%5D%5D%28%29%0A%20%20%20%20%20%20%20%20for%20edge%20in%20edges%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B0%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_vertex%28edge%5B1%5D%29%0A%20%20%20%20%20%20%20%20%20%20%20%20self.add_edge%28edge%5B0%5D%2C%20edge%5B1%5D%29%0A%0A%20%20%20%20def%20size%28self%29%20-%3E%20int%3A%0A%20%20%20%20%20%20%20%20return%20len%28self.adj_list%29%0A%0A%20%20%20%20def%20add_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.append%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.append%28vet1%29%0A%0A%20%20%20%20def%20remove_edge%28self%2C%20vet1%3A%20Vertex%2C%20vet2%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet1%20not%20in%20self.adj_list%20or%20vet2%20not%20in%20self.adj_list%20or%20vet1%20%3D%3D%20vet2%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet1%5D.remove%28vet2%29%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet2%5D.remove%28vet1%29%0A%0A%20%20%20%20def%20add_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20self.adj_list%5Bvet%5D%20%3D%20%5B%5D%0A%0A%20%20%20%20def%20remove_vertex%28self%2C%20vet%3A%20Vertex%29%3A%0A%20%20%20%20%20%20%20%20if%20vet%20not%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError%28%29%0A%20%20%20%20%20%20%20%20self.adj_list.pop%28vet%29%0A%20%20%20%20%20%20%20%20for%20vertex%20in%20self.adj_list%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20vet%20in%20self.adj_list%5Bvertex%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20self.adj_list%5Bvertex%5D.remove%28vet%29%0A%27Driver%20Code%27%0Aif%20__name__%20%3D%3D%20%27__main__%27%3A%0A%20%20%20%20v%20%3D%20vals_to_vets%28%5B1%2C%203%2C%202%2C%205%2C%204%5D%29%0A%20%20%20%20edges%20%3D%20%5B%5Bv%5B0%5D%2C%20v%5B1%5D%5D%2C%20%5Bv%5B0%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B1%5D%2C%20v%5B2%5D%5D%2C%20%5Bv%5B2%5D%2C%20v%5B3%5D%5D%2C%20%5Bv%5B2%5D%2C%20v%5B4%5D%5D%2C%20%5Bv%5B3%5D%2C%20v%5B4%5D%5D%5D%0A%20%20%20%20graph%20%3D%20GraphAdjList%28edges%29%0A%20%20%20%20del%20edges%0A%20%20%20%20graph.add_edge%28v%5B0%5D%2C%20v%5B2%5D%29%0A%20%20%20%20graph.remove_edge%28v%5B0%5D%2C%20v%5B1%5D%29%0A%20%20%20%20v5%20%3D%20Vertex%286%29%0A%20%20%20%20graph.add_vertex%28v5%29%0A%20%20%20%20graph.remove_vertex%28v%5B1%5D%29&codeDivHeight=800&codeDivWidth=600&cumulative=false&curInstr=39&heapPrimitives=nevernest&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false" target="_blank" rel="noopener noreferrer">Во весь экран &gt;</a></div></p>
</details>
<h2 id="923">9.2.3 &nbsp; Сравнение эффективности<a class="headerlink" href="#923" title="Permanent link">&para;</a></h2>
<p>Пусть в графе имеется <span class="arithmatex">\(n\)</span> вершин и <span class="arithmatex">\(m\)</span> ребер. В таблице 9-2 сравниваются временная и пространственная эффективность матрицы смежности и списка смежности. Обрати внимание: список смежности (связный список) соответствует реализации из этой статьи, а список смежности (хеш-таблица) означает вариант, где все списки заменены хеш-таблицами.</p>
<p>Пусть в графе имеется <span class="arithmatex">\(n\)</span> вершин и <span class="arithmatex">\(m\)</span> ребер. В таблице 9-2 сравниваются временная и пространственная эффективность матрицы смежности и списка смежности. Обратите внимание: список смежности (связный список) соответствует реализации из этой статьи, а список смежности (хеш-таблица) означает вариант, в котором все списки заменены хеш-таблицами.</p>
<p align="center"> Таблица 9-2 &nbsp; Сравнение матрицы смежности и списка смежности </p>
<div class="center-table">
@@ -6755,7 +6755,7 @@
</tbody>
</table>
</div>
<p>Если смотреть только на таблицу, может показаться, что список смежности на основе хеш-таблицы является лучшим и по времени, и по памяти. Но на практике операции над ребрами в матрице смежности часто выполняются быстрее, потому что там нужен лишь один доступ к массиву или одно присваивание. В целом матрица смежности воплощает принцип "обмен пространства на время", а список смежности - принцип "обмен времени на пространство".</p>
<p>Если смотреть только на таблицу, может показаться, что список смежности на основе хеш-таблицы является лучшим и по времени, и по памяти. Но на практике операции над ребрами в матрице смежности обычно выполняются быстрее, потому что там нужен лишь один доступ к массиву или одно присваивание. В целом матрица смежности воплощает принцип "обмена пространства на время", а список смежности - принцип "обмена времени на пространство".</p>
<!-- Source file information -->
+49 -49
View File
@@ -65,8 +65,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
@@ -574,7 +574,7 @@
<span class="md-ellipsis">
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
@@ -596,7 +596,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
</label>
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 Что такое структуры данных и алгоритмы
1.2 Что такое алгоритм
@@ -1181,7 +1181,7 @@
<span class="md-ellipsis">
Глава 4. Массив и связный список
Глава 4. Массивы и списки
@@ -1203,7 +1203,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 4. Массив и связный список
Глава 4. Массивы и списки
</label>
@@ -1309,7 +1309,7 @@
<span class="md-ellipsis">
4.4 Память и кеш *
4.4 Оперативная память и кэш *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
Глава 6. Хеширование
Глава 6. Хеш-таблицы
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 6. Хеширование
Глава 6. Хеш-таблицы
</label>
@@ -1691,7 +1691,7 @@
<span class="md-ellipsis">
6.3 Хеш-алгоритмы
6.3 Алгоритмы хеширования
@@ -1786,7 +1786,7 @@
<span class="md-ellipsis">
Глава 7. Дерево
Глава 7. Деревья
@@ -1808,7 +1808,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 7. Дерево
Глава 7. Деревья
</label>
@@ -1886,7 +1886,7 @@
<span class="md-ellipsis">
7.3 Представление дерева массивом
7.3 Представление двоичного дерева массивом
@@ -1970,7 +1970,7 @@
<span class="md-ellipsis">
7.6 Резюме
7.6 Краткие итоги
@@ -2133,7 +2133,7 @@
<span class="md-ellipsis">
8.3 Задача Top-K
8.3 Задача Top-k
@@ -2226,7 +2226,7 @@
<span class="md-ellipsis">
Глава 9. Граф
Глава 9. Графы
@@ -2248,7 +2248,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 9. Граф
Глава 9. Графы
</label>
@@ -2298,7 +2298,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2480,7 +2480,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2619,7 +2619,7 @@
<span class="md-ellipsis">
10.2 Точка вставки двоичного поиска
10.2 Двоичный поиск точки вставки
@@ -2647,7 +2647,7 @@
<span class="md-ellipsis">
10.3 Граничные случаи двоичного поиска
10.3 Двоичный поиск границ
@@ -2675,7 +2675,7 @@
<span class="md-ellipsis">
10.4 Стратегия оптимизации через хеширование
10.4 Стратегии оптимизации хеширования
@@ -2703,7 +2703,7 @@
<span class="md-ellipsis">
10.5 Алгоритмы поиска: новый взгляд
10.5 Переосмысление алгоритмов поиска
@@ -2908,7 +2908,7 @@
<span class="md-ellipsis">
11.3 Пузырьковая сортировка
11.3 Сортировка пузырьком
@@ -2936,7 +2936,7 @@
<span class="md-ellipsis">
11.4 Сортировка вставкой
11.4 Сортировка вставками
@@ -3241,7 +3241,7 @@
<span class="md-ellipsis">
12.1 Алгоритмы разделяй и властвуй
12.1 Стратегия разделяй и властвуй
@@ -3269,7 +3269,7 @@
<span class="md-ellipsis">
12.2 Стратегия поиска разделяй и властвуй
12.2 Поисковая стратегия разделяй и властвуй
@@ -3546,7 +3546,7 @@
<span class="md-ellipsis">
13.4 Задача о $n$ ферзях
13.4 Задача о n ферзях
@@ -3687,7 +3687,7 @@
<span class="md-ellipsis">
14.1 Введение в динамическое программирование
14.1 Первое знакомство с динамическим программированием
@@ -3799,7 +3799,7 @@
<span class="md-ellipsis">
14.5 Задача о неограниченном рюкзаке
14.5 Задача о полном рюкзаке
@@ -4467,24 +4467,24 @@
<!-- Page content -->
<h1 id="93">9.3 &nbsp; Обход графа<a class="headerlink" href="#93" title="Permanent link">&para;</a></h1>
<p>Дерево представляет отношение "один ко многим", а граф имеет более высокую степень свободы и может выражать произвольные отношения "многие ко многим". Поэтому мы можем рассматривать дерево как частный случай графа. Очевидно, что <strong>операции обхода дерева также являются частным случаем операций обхода графа</strong>.</p>
<p>И графы, и деревья требуют использования поисковых алгоритмов для реализации обхода. Способы обхода графа также делятся на два типа: <u>обход в ширину</u> и <u>обход в глубину</u>.</p>
<p>Дерево представляет отношение "один ко многим", тогда как граф обладает большей свободой и может выражать произвольные отношения "многие ко многим". Поэтому дерево можно рассматривать как частный случай графа. Очевидно, что <strong>операции обхода дерева также являются частным случаем операций обхода графа</strong>.</p>
<p>И графы, и деревья требуют применения алгоритмов обхода. Способы обхода графа также делятся на два типа: <u>обход в ширину</u> и <u>обход в глубину</u>.</p>
<h2 id="931">9.3.1 &nbsp; Обход в ширину<a class="headerlink" href="#931" title="Permanent link">&para;</a></h2>
<p><strong>Обход в ширину - это способ обхода "от близкого к далекому": начиная с некоторого узла, мы всегда в первую очередь посещаем ближайшие вершины и слой за слоем расширяемся наружу</strong>. Как показано на рисунке 9-9, начиная с вершины в левом верхнем углу, мы сначала обходим все смежные вершины этой вершины, затем все смежные вершины следующей вершины и так далее, пока не будут посещены все вершины.</p>
<p><strong>Обход в ширину - это способ обхода от ближнего к дальнему, при котором начиная с некоторого узла сначала посещают ближайшие вершины, а затем слой за слоем расширяются наружу</strong>. Как показано на рисунке 9-9, начиная с вершины в левом верхнем углу, мы сначала обходим все смежные вершины этой вершины, затем все смежные вершины следующей вершины и так далее, пока не будут посещены все вершины.</p>
<p><img alt="Обход графа в ширину" class="animation-figure" src="../graph_traversal.assets/graph_bfs.png" /></p>
<p align="center"> Рисунок 9-9 &nbsp; Обход графа в ширину </p>
<h3 id="1">1. &nbsp; Реализация алгоритма<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<p>BFS обычно реализуется с помощью очереди, код приведен ниже. Очередь обладает свойством "первым пришел - первым вышел", что хорошо соответствует идее BFS "от близкого к далекому".</p>
<p>BFS обычно реализуется с помощью очереди, код приведен ниже. Очередь обладает свойством "первым пришел - первым вышел", что хорошо соответствует идее BFS "от ближнего к дальнему".</p>
<ol>
<li>Поместить стартовую вершину обхода <code>startVet</code> в очередь и запустить цикл.</li>
<li>На каждой итерации цикла извлекать вершину из головы очереди и записывать факт ее посещения, после чего добавлять все смежные вершины этой вершины в хвост очереди.</li>
<li>На каждой итерации цикла извлекать вершину из головы очереди и записывать ее посещение, после чего добавлять все смежные вершины этой вершины в хвост очереди.</li>
<li>Повторять шаг <code>2.</code> до тех пор, пока не будут посещены все вершины.</li>
</ol>
<p>Чтобы предотвратить повторный обход вершин, нам нужен хеш-набор <code>visited</code> , в котором будет записываться, какие узлы уже посещены.</p>
<p>Чтобы предотвратить повторный обход вершин, нам нужно хеш-множество <code>visited</code> , в котором записывается, какие вершины уже посещены.</p>
<div class="admonition tip">
<p class="admonition-title">Tip</p>
<p>Хеш-набор можно рассматривать как хеш-таблицу, которая хранит только <code>key</code> и не хранит <code>value</code> . Он позволяет выполнять добавление, удаление, поиск и изменение <code>key</code> за <span class="arithmatex">\(O(1)\)</span> времени. Благодаря уникальности <code>key</code> хеш-набор обычно используется, например, для устранения повторов.</p>
<p>Хеш-множество можно рассматривать как хеш-таблицу, которая хранит только <code>key</code> и не хранит <code>value</code> . Оно позволяет выполнять добавление, удаление и проверку наличия <code>key</code> за <span class="arithmatex">\(O(1)\)</span> времени. Благодаря уникальности <code>key</code> хеш-множество обычно используется, например, для устранения повторов.</p>
</div>
<div class="tabbed-set tabbed-alternate" data-tabs="1:13"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><input id="__tabbed_1_3" name="__tabbed_1" type="radio" /><input id="__tabbed_1_4" name="__tabbed_1" type="radio" /><input id="__tabbed_1_5" name="__tabbed_1" type="radio" /><input id="__tabbed_1_6" name="__tabbed_1" type="radio" /><input id="__tabbed_1_7" name="__tabbed_1" type="radio" /><input id="__tabbed_1_8" name="__tabbed_1" type="radio" /><input id="__tabbed_1_9" name="__tabbed_1" type="radio" /><input id="__tabbed_1_10" name="__tabbed_1" type="radio" /><input id="__tabbed_1_11" name="__tabbed_1" type="radio" /><input id="__tabbed_1_12" name="__tabbed_1" type="radio" /><input id="__tabbed_1_13" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Python</label><label for="__tabbed_1_2">C++</label><label for="__tabbed_1_3">Java</label><label for="__tabbed_1_4">C#</label><label for="__tabbed_1_5">Go</label><label for="__tabbed_1_6">Swift</label><label for="__tabbed_1_7">JS</label><label for="__tabbed_1_8">TS</label><label for="__tabbed_1_9">Dart</label><label for="__tabbed_1_10">Rust</label><label for="__tabbed_1_11">C</label><label for="__tabbed_1_12">Kotlin</label><label for="__tabbed_1_13">Ruby</label></div>
<div class="tabbed-content">
@@ -4956,18 +4956,18 @@
<div class="admonition question">
<p class="admonition-title">Является ли последовательность обхода в ширину единственной?</p>
<p>Нет. Обход в ширину требует только соблюдения порядка "от близкого к далекому", <strong>а порядок обхода нескольких вершин на одинаковом расстоянии может произвольно меняться</strong>. Например, на рисунке 9-10 можно поменять местами порядок посещения вершин <span class="arithmatex">\(1\)</span> и <span class="arithmatex">\(3\)</span> , а также в произвольном порядке переставить вершины <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(4\)</span>, <span class="arithmatex">\(6\)</span> .</p>
<p>Нет. Обход в ширину требует только соблюдения порядка "от ближнего к дальнему", <strong>а порядок обхода нескольких вершин на одинаковом расстоянии может произвольно меняться</strong>. Например, на рисунке 9-10 можно поменять местами порядок посещения вершин <span class="arithmatex">\(1\)</span> и <span class="arithmatex">\(3\)</span> , а вершины <span class="arithmatex">\(2\)</span>, <span class="arithmatex">\(4\)</span>, <span class="arithmatex">\(6\)</span> также можно переставлять произвольно.</p>
</div>
<h3 id="2">2. &nbsp; Анализ сложности<a class="headerlink" href="#2" title="Permanent link">&para;</a></h3>
<p><strong>Временная сложность</strong>: все вершины по одному разу помещаются в очередь и извлекаются из нее, что требует <span class="arithmatex">\(O(|V|)\)</span> времени; при обходе смежных вершин, поскольку граф неориентированный, все ребра будут посещены по <span class="arithmatex">\(2\)</span> раза, что требует <span class="arithmatex">\(O(2|E|)\)</span> времени; в сумме получается <span class="arithmatex">\(O(|V| + |E|)\)</span> .</p>
<p><strong>Пространственная сложность</strong>: список <code>res</code> , хеш-набор <code>visited</code> и очередь <code>que</code> в худшем случае могут содержать до <span class="arithmatex">\(|V|\)</span> вершин, поэтому требуется <span class="arithmatex">\(O(|V|)\)</span> памяти.</p>
<p><strong>Пространственная сложность</strong>: список <code>res</code> , хеш-множество <code>visited</code> и очередь <code>que</code> в худшем случае могут содержать до <span class="arithmatex">\(|V|\)</span> вершин, поэтому требуется <span class="arithmatex">\(O(|V|)\)</span> памяти.</p>
<h2 id="932">9.3.2 &nbsp; Обход в глубину<a class="headerlink" href="#932" title="Permanent link">&para;</a></h2>
<p><strong>Обход в глубину - это способ обхода, при котором сначала идут до самого конца, а когда дальше идти нельзя, откатываются назад</strong>. Как показано на рисунке 9-11, начиная с вершины в левом верхнем углу, мы выбираем некоторую смежную вершину текущей вершины, идем до упора, затем возвращаемся назад, снова идем до упора и так далее, пока не будут посещены все вершины.</p>
<p><strong>Обход в глубину - это способ обхода, при котором сначала идут до самого конца, а когда дальше идти нельзя, возвращаются назад</strong>. Как показано на рисунке 9-11, начиная с вершины в левом верхнем углу, мы выбираем некоторую смежную вершину текущей вершины, идем до упора, затем возвращаемся назад, снова идем до упора и так далее, пока не будут посещены все вершины.</p>
<p><img alt="Обход графа в глубину" class="animation-figure" src="../graph_traversal.assets/graph_dfs.png" /></p>
<p align="center"> Рисунок 9-11 &nbsp; Обход графа в глубину </p>
<h3 id="1_1">1. &nbsp; Реализация алгоритма<a class="headerlink" href="#1_1" title="Permanent link">&para;</a></h3>
<p>Такой алгоритмический шаблон "дойти до конца и вернуться" обычно реализуется через рекурсию. Подобно обходу в ширину, в обходе в глубину мы также используем хеш-набор <code>visited</code> для записи уже посещенных вершин и тем самым избегаем повторного посещения.</p>
<p>Такой алгоритмический шаблон "дойти до конца и вернуться" обычно реализуется через рекурсию. Подобно обходу в ширину, в обходе в глубину мы также используем хеш-множество <code>visited</code> для записи уже посещенных вершин и тем самым избегаем повторного посещения.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:13"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><input id="__tabbed_3_3" name="__tabbed_3" type="radio" /><input id="__tabbed_3_4" name="__tabbed_3" type="radio" /><input id="__tabbed_3_5" name="__tabbed_3" type="radio" /><input id="__tabbed_3_6" name="__tabbed_3" type="radio" /><input id="__tabbed_3_7" name="__tabbed_3" type="radio" /><input id="__tabbed_3_8" name="__tabbed_3" type="radio" /><input id="__tabbed_3_9" name="__tabbed_3" type="radio" /><input id="__tabbed_3_10" name="__tabbed_3" type="radio" /><input id="__tabbed_3_11" name="__tabbed_3" type="radio" /><input id="__tabbed_3_12" name="__tabbed_3" type="radio" /><input id="__tabbed_3_13" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">Python</label><label for="__tabbed_3_2">C++</label><label for="__tabbed_3_3">Java</label><label for="__tabbed_3_4">C#</label><label for="__tabbed_3_5">Go</label><label for="__tabbed_3_6">Swift</label><label for="__tabbed_3_7">JS</label><label for="__tabbed_3_8">TS</label><label for="__tabbed_3_9">Dart</label><label for="__tabbed_3_10">Rust</label><label for="__tabbed_3_11">C</label><label for="__tabbed_3_12">Kotlin</label><label for="__tabbed_3_13">Ruby</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
@@ -5349,8 +5349,8 @@
</details>
<p>Алгоритмический процесс обхода в глубину показан на рисунках ниже.</p>
<ul>
<li><strong>Прямая пунктирная линия обозначает нисходящее рекурсивное развертывание</strong> , то есть запуск нового рекурсивного метода для посещения новой вершины.</li>
<li><strong>Изогнутая пунктирная линия обозначает обратный возврат по рекурсии</strong> , то есть данный рекурсивный метод завершился и управление вернулось туда, откуда он был вызван.</li>
<li><strong>Прямая пунктирная линия обозначает нисходящую рекурсию</strong> , то есть запуск нового рекурсивного метода для посещения новой вершины.</li>
<li><strong>Изогнутая пунктирная линия обозначает восходящую рекурсию</strong> , то есть данный рекурсивный метод завершился и управление вернулось туда, откуда он был вызван.</li>
</ul>
<p>Чтобы лучше понять алгоритм, рекомендуется совместить рисунки ниже с кодом и мысленно проследить весь процесс DFS, включая моменты запуска и возврата каждого рекурсивного вызова.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="4:11"><input checked="checked" id="__tabbed_4_1" name="__tabbed_4" type="radio" /><input id="__tabbed_4_2" name="__tabbed_4" type="radio" /><input id="__tabbed_4_3" name="__tabbed_4" type="radio" /><input id="__tabbed_4_4" name="__tabbed_4" type="radio" /><input id="__tabbed_4_5" name="__tabbed_4" type="radio" /><input id="__tabbed_4_6" name="__tabbed_4" type="radio" /><input id="__tabbed_4_7" name="__tabbed_4" type="radio" /><input id="__tabbed_4_8" name="__tabbed_4" type="radio" /><input id="__tabbed_4_9" name="__tabbed_4" type="radio" /><input id="__tabbed_4_10" name="__tabbed_4" type="radio" /><input id="__tabbed_4_11" name="__tabbed_4" type="radio" /><div class="tabbed-labels"><label for="__tabbed_4_1">&lt;1&gt;</label><label for="__tabbed_4_2">&lt;2&gt;</label><label for="__tabbed_4_3">&lt;3&gt;</label><label for="__tabbed_4_4">&lt;4&gt;</label><label for="__tabbed_4_5">&lt;5&gt;</label><label for="__tabbed_4_6">&lt;6&gt;</label><label for="__tabbed_4_7">&lt;7&gt;</label><label for="__tabbed_4_8">&lt;8&gt;</label><label for="__tabbed_4_9">&lt;9&gt;</label><label for="__tabbed_4_10">&lt;10&gt;</label><label for="__tabbed_4_11">&lt;11&gt;</label></div>
@@ -5399,7 +5399,7 @@
</div>
<h3 id="2_1">2. &nbsp; Анализ сложности<a class="headerlink" href="#2_1" title="Permanent link">&para;</a></h3>
<p><strong>Временная сложность</strong>: все вершины будут посещены по <span class="arithmatex">\(1\)</span> разу, что требует <span class="arithmatex">\(O(|V|)\)</span> времени; все ребра будут посещены по <span class="arithmatex">\(2\)</span> раза, что требует <span class="arithmatex">\(O(2|E|)\)</span> времени; суммарно получается <span class="arithmatex">\(O(|V| + |E|)\)</span> .</p>
<p><strong>Пространственная сложность</strong>: число вершин в списке <code>res</code> и хеш-наборе <code>visited</code> в худшем случае достигает <span class="arithmatex">\(|V|\)</span> , максимальная глубина рекурсии тоже равна <span class="arithmatex">\(|V|\)</span> , поэтому требуется <span class="arithmatex">\(O(|V|)\)</span> памяти.</p>
<p><strong>Пространственная сложность</strong>: число вершин в списке <code>res</code> и хеш-множестве <code>visited</code> в худшем случае достигает <span class="arithmatex">\(|V|\)</span> , максимальная глубина рекурсии тоже равна <span class="arithmatex">\(|V|\)</span> , поэтому требуется <span class="arithmatex">\(O(|V|)\)</span> памяти.</p>
<!-- Source file information -->
@@ -5422,7 +5422,7 @@ aria-label="Нижний колонтитул"
<a
href="../graph_operations/"
class="md-footer__link md-footer__link--prev"
aria-label="Назад: 9.2 Базовые операции над графами"
aria-label="Назад: 9.2 Базовые операции графа"
rel="prev"
>
<div class="md-footer__button md-icon">
@@ -5434,7 +5434,7 @@ aria-label="Нижний колонтитул"
Назад
</span>
<div class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
</div>
</div>
</a>
@@ -5446,7 +5446,7 @@ aria-label="Нижний колонтитул"
<a
href="../summary/"
class="md-footer__link md-footer__link--next"
aria-label="Вперед: 9.4 Резюме"
aria-label="Вперед: 9.4 Краткие итоги"
rel="next"
>
<div class="md-footer__title">
@@ -5454,7 +5454,7 @@ aria-label="Нижний колонтитул"
Вперед
</span>
<div class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
</div>
</div>
<div class="md-footer__button md-icon">
+35 -35
View File
@@ -65,8 +65,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
@@ -574,7 +574,7 @@
<span class="md-ellipsis">
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
@@ -596,7 +596,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
</label>
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 Что такое структуры данных и алгоритмы
1.2 Что такое алгоритм
@@ -1181,7 +1181,7 @@
<span class="md-ellipsis">
Глава 4. Массив и связный список
Глава 4. Массивы и списки
@@ -1203,7 +1203,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 4. Массив и связный список
Глава 4. Массивы и списки
</label>
@@ -1309,7 +1309,7 @@
<span class="md-ellipsis">
4.4 Память и кеш *
4.4 Оперативная память и кэш *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
Глава 6. Хеширование
Глава 6. Хеш-таблицы
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 6. Хеширование
Глава 6. Хеш-таблицы
</label>
@@ -1691,7 +1691,7 @@
<span class="md-ellipsis">
6.3 Хеш-алгоритмы
6.3 Алгоритмы хеширования
@@ -1786,7 +1786,7 @@
<span class="md-ellipsis">
Глава 7. Дерево
Глава 7. Деревья
@@ -1808,7 +1808,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 7. Дерево
Глава 7. Деревья
</label>
@@ -1886,7 +1886,7 @@
<span class="md-ellipsis">
7.3 Представление дерева массивом
7.3 Представление двоичного дерева массивом
@@ -1970,7 +1970,7 @@
<span class="md-ellipsis">
7.6 Резюме
7.6 Краткие итоги
@@ -2133,7 +2133,7 @@
<span class="md-ellipsis">
8.3 Задача Top-K
8.3 Задача Top-k
@@ -2226,7 +2226,7 @@
<span class="md-ellipsis">
Глава 9. Граф
Глава 9. Графы
@@ -2248,7 +2248,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 9. Граф
Глава 9. Графы
</label>
@@ -2298,7 +2298,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2354,7 +2354,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2493,7 +2493,7 @@
<span class="md-ellipsis">
10.2 Точка вставки двоичного поиска
10.2 Двоичный поиск точки вставки
@@ -2521,7 +2521,7 @@
<span class="md-ellipsis">
10.3 Граничные случаи двоичного поиска
10.3 Двоичный поиск границ
@@ -2549,7 +2549,7 @@
<span class="md-ellipsis">
10.4 Стратегия оптимизации через хеширование
10.4 Стратегии оптимизации хеширования
@@ -2577,7 +2577,7 @@
<span class="md-ellipsis">
10.5 Алгоритмы поиска: новый взгляд
10.5 Переосмысление алгоритмов поиска
@@ -2782,7 +2782,7 @@
<span class="md-ellipsis">
11.3 Пузырьковая сортировка
11.3 Сортировка пузырьком
@@ -2810,7 +2810,7 @@
<span class="md-ellipsis">
11.4 Сортировка вставкой
11.4 Сортировка вставками
@@ -3115,7 +3115,7 @@
<span class="md-ellipsis">
12.1 Алгоритмы разделяй и властвуй
12.1 Стратегия разделяй и властвуй
@@ -3143,7 +3143,7 @@
<span class="md-ellipsis">
12.2 Стратегия поиска разделяй и властвуй
12.2 Поисковая стратегия разделяй и властвуй
@@ -3420,7 +3420,7 @@
<span class="md-ellipsis">
13.4 Задача о $n$ ферзях
13.4 Задача о n ферзях
@@ -3561,7 +3561,7 @@
<span class="md-ellipsis">
14.1 Введение в динамическое программирование
14.1 Первое знакомство с динамическим программированием
@@ -3673,7 +3673,7 @@
<span class="md-ellipsis">
14.5 Задача о неограниченном рюкзаке
14.5 Задача о полном рюкзаке
@@ -4277,15 +4277,15 @@
<p><img alt="Графы" class="cover-image" src="../assets/covers/chapter_graph.jpg" /></p>
<div class="admonition abstract">
<p class="admonition-title">Abstract</p>
<p>На жизненном пути мы подобны узлам, соединенным бесчисленными невидимыми ребрами.</p>
<p>Каждая встреча и каждое расставание оставляют в этой огромной сети свой особый след.</p>
<p>В жизни мы похожи на вершины, соединенные множеством невидимых ребер.</p>
<p>Каждая встреча и каждое расставание оставляют в этой огромной сети свой след.</p>
</div>
<h2 id="_1">Содержание главы<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<ul>
<li><a href="graph/">9.1 &nbsp; Граф</a></li>
<li><a href="graph_operations/">9.2 &nbsp; Базовые операции над графами</a></li>
<li><a href="graph_operations/">9.2 &nbsp; Базовые операции графа</a></li>
<li><a href="graph_traversal/">9.3 &nbsp; Обход графа</a></li>
<li><a href="summary/">9.4 &nbsp; Резюме</a></li>
<li><a href="summary/">9.4 &nbsp; Краткие итоги</a></li>
</ul>
<!-- Source file information -->
+37 -37
View File
@@ -65,8 +65,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Noto+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Noto Sans";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=PT+Sans:300,300i,400,400i,500,500i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"PT Sans";--md-code-font:"JetBrains Mono"}</style>
@@ -574,7 +574,7 @@
<span class="md-ellipsis">
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
@@ -596,7 +596,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 1. Знакомство с алгоритмами
Глава 1. Введение в алгоритмы
</label>
@@ -646,7 +646,7 @@
<span class="md-ellipsis">
1.2 Что такое структуры данных и алгоритмы
1.2 Что такое алгоритм
@@ -1181,7 +1181,7 @@
<span class="md-ellipsis">
Глава 4. Массив и связный список
Глава 4. Массивы и списки
@@ -1203,7 +1203,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 4. Массив и связный список
Глава 4. Массивы и списки
</label>
@@ -1309,7 +1309,7 @@
<span class="md-ellipsis">
4.4 Память и кеш *
4.4 Оперативная память и кэш *
@@ -1591,7 +1591,7 @@
<span class="md-ellipsis">
Глава 6. Хеширование
Глава 6. Хеш-таблицы
@@ -1613,7 +1613,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 6. Хеширование
Глава 6. Хеш-таблицы
</label>
@@ -1691,7 +1691,7 @@
<span class="md-ellipsis">
6.3 Хеш-алгоритмы
6.3 Алгоритмы хеширования
@@ -1786,7 +1786,7 @@
<span class="md-ellipsis">
Глава 7. Дерево
Глава 7. Деревья
@@ -1808,7 +1808,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 7. Дерево
Глава 7. Деревья
</label>
@@ -1886,7 +1886,7 @@
<span class="md-ellipsis">
7.3 Представление дерева массивом
7.3 Представление двоичного дерева массивом
@@ -1970,7 +1970,7 @@
<span class="md-ellipsis">
7.6 Резюме
7.6 Краткие итоги
@@ -2133,7 +2133,7 @@
<span class="md-ellipsis">
8.3 Задача Top-K
8.3 Задача Top-k
@@ -2226,7 +2226,7 @@
<span class="md-ellipsis">
Глава 9. Граф
Глава 9. Графы
@@ -2248,7 +2248,7 @@
<span class="md-nav__icon md-icon"></span>
Глава 9. Граф
Глава 9. Графы
</label>
@@ -2298,7 +2298,7 @@
<span class="md-ellipsis">
9.2 Базовые операции над графами
9.2 Базовые операции графа
@@ -2363,7 +2363,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2381,7 +2381,7 @@
<span class="md-ellipsis">
9.4 Резюме
9.4 Краткие итоги
@@ -2563,7 +2563,7 @@
<span class="md-ellipsis">
10.2 Точка вставки двоичного поиска
10.2 Двоичный поиск точки вставки
@@ -2591,7 +2591,7 @@
<span class="md-ellipsis">
10.3 Граничные случаи двоичного поиска
10.3 Двоичный поиск границ
@@ -2619,7 +2619,7 @@
<span class="md-ellipsis">
10.4 Стратегия оптимизации через хеширование
10.4 Стратегии оптимизации хеширования
@@ -2647,7 +2647,7 @@
<span class="md-ellipsis">
10.5 Алгоритмы поиска: новый взгляд
10.5 Переосмысление алгоритмов поиска
@@ -2852,7 +2852,7 @@
<span class="md-ellipsis">
11.3 Пузырьковая сортировка
11.3 Сортировка пузырьком
@@ -2880,7 +2880,7 @@
<span class="md-ellipsis">
11.4 Сортировка вставкой
11.4 Сортировка вставками
@@ -3185,7 +3185,7 @@
<span class="md-ellipsis">
12.1 Алгоритмы разделяй и властвуй
12.1 Стратегия разделяй и властвуй
@@ -3213,7 +3213,7 @@
<span class="md-ellipsis">
12.2 Стратегия поиска разделяй и властвуй
12.2 Поисковая стратегия разделяй и властвуй
@@ -3490,7 +3490,7 @@
<span class="md-ellipsis">
13.4 Задача о $n$ ферзях
13.4 Задача о n ферзях
@@ -3631,7 +3631,7 @@
<span class="md-ellipsis">
14.1 Введение в динамическое программирование
14.1 Первое знакомство с динамическим программированием
@@ -3743,7 +3743,7 @@
<span class="md-ellipsis">
14.5 Задача о неограниченном рюкзаке
14.5 Задача о полном рюкзаке
@@ -4359,11 +4359,11 @@
<ul>
<li>Граф состоит из вершин и ребер и может быть задан как множество вершин и множество ребер.</li>
<li>По сравнению с линейными отношениями (связный список) и отношениями разделения (дерево), сетевые отношения (граф) обладают большей свободой и потому более сложны.</li>
<li>Ребра ориентированного графа имеют направление, в связном графе любые вершины достижимы друг из друга, а в взвешенном графе каждое ребро несет переменную веса.</li>
<li>Матрица смежности использует матрицу для представления графа: каждая строка и каждый столбец соответствуют вершине, а элементы матрицы показывают, есть между двумя вершинами ребро или нет. Матрица смежности очень эффективна для операций добавления, удаления, поиска и изменения, но расходует больше памяти.</li>
<li>Ребра ориентированного графа имеют направление, в связном графе любые вершины достижимы, а во взвешенном графе каждое ребро содержит переменную веса.</li>
<li>Матрица смежности использует матрицу для представления графа: каждая строка и каждый столбец соответствуют вершине, а элементы матрицы показывают, есть между двумя вершинами ребро или нет. Матрица смежности эффективна в операциях добавления, удаления, поиска и изменения, но расходует больше памяти.</li>
<li>Список смежности использует несколько списков для представления графа; <span class="arithmatex">\(i\)</span>-й список соответствует вершине <span class="arithmatex">\(i\)</span> и хранит все ее смежные вершины. По сравнению с матрицей смежности список смежности экономит пространство, но для поиска ребра в нем приходится обходить список, поэтому по времени он уступает.</li>
<li>Когда списки в списке смежности становятся слишком длинными, их можно преобразовать в красно-черное дерево или хеш-таблицу, чтобы ускорить поиск.</li>
<li>С точки зрения алгоритмической идеи матрица смежности отражает принцип "обмен пространства на время", а список смежности - принцип "обмена времени на пространство".</li>
<li>Когда списки в списке смежности становятся слишком длинными, их можно преобразовать в красно-черное дерево или хеш-таблицу, чтобы повысить эффективность поиска.</li>
<li>С точки зрения алгоритмической идеи матрица смежности отражает принцип "обмена пространства на время", а список смежности - принцип "обмена времени на пространство".</li>
<li>Графы можно использовать для моделирования различных реальных систем, таких как социальные сети, линии метро и так далее.</li>
<li>Дерево является частным случаем графа, а обход дерева - частным случаем обхода графа.</li>
<li>Обход графа в ширину представляет собой способ поиска, который расширяется от ближнего к дальнему и обычно реализуется с помощью очереди.</li>
@@ -4371,7 +4371,7 @@
</ul>
<h3 id="2-q-a">2. &nbsp; Q &amp; A<a class="headerlink" href="#2-q-a" title="Permanent link">&para;</a></h3>
<p><strong>Q</strong>: Что считается путем: последовательность вершин или последовательность ребер?</p>
<p>Определение в разных языковых версиях Википедии различается: в английской версии путь определяется как "последовательность ребер", а в китайской версии - как "последовательность вершин". В английской версии исходная формулировка выглядит так: In graph theory, a path in a graph is a finite or infinite sequence of edges which joins a sequence of vertices.</p>
<p>Определение в разных языковых версиях Википедии различается: в английской версии путь определяется как "последовательность ребер", а в русской версии - как "последовательность вершин". В английской версии исходная формулировка выглядит так: In graph theory, a path in a graph is a finite or infinite sequence of edges which joins a sequence of vertices.</p>
<p>В этой книге путь рассматривается как последовательность ребер, а не как последовательность вершин. Причина в том, что между двумя вершинами может существовать несколько ребер, и в таком случае каждому ребру соответствует свой путь.</p>
<p><strong>Q</strong>: Есть ли в несвязном графе вершины, до которых нельзя дойти?</p>
<p>В несвязном графе, начиная из некоторой вершины, по крайней мере одна вершина оказывается недостижимой. Чтобы обойти весь несвязный граф, нужно задать несколько стартовых точек и обойти все связные компоненты графа.</p>