El contenido de este capítulo está implementado en Java, almacén de código de Github: https://github.com/ZhekaiLi/Code/tree/main/Graph/src
¡Ver las imágenes en el artículo puede requerir acceso científico a Internet!Debido a que github se usa para administrar imágenes, si hay una situación que no se puede cargar, voltee la pared
[Referencia] imooc Mr. Bobo: Fun Algorithm Series - Graph Theory Essentials for Interview and Promotion (Java Edition)
[Enlaces a blogs anteriores]
Algoritmos de teoría de grafos (1, 2): clasificación de grafos, conceptos básicos de grafos (gráficos no dirigidos y gráficos dirigidos, gráficos no ponderados, gráficos acíclicos, gráficos completos, gráficos bipartitos; gráficos simples, componentes de gráficos conectados, expansión árbol de gráficos, subgráficos y gráficos principales)
algoritmo de teoría de gráficos (3): representación básica de gráficos (matriz de adyacencia, lista de adyacencia, comparación de matriz de adyacencia y lista de adyacencia)
algoritmo de teoría de gráficos (4): primera profundidad de gráficos
Teoría de gráficos DFS transversal Algoritmo (5): Amplitud de gráfico Primer recorrido BFS
Algoritmo de teoría de gráficos (6): LeetCode Ejercicio de algoritmo de teoría de gráficos (785. Juicio de gráfico bipartito, 695. Área máxima de isla, Algoritmo de relleno de inundación, Verificación de unión)
4 Recorrido primero en profundidad de DFS para gráficos
(Sobre el recorrido del árbol por delante, por en medio, por detrás y por capas, hay un blog que lo resume muy bien: https://blog.csdn.net/zl6481033/article/details/81009388 )
Veamos primero el Recorrido primero en profundidad del árbol (anteriormente Recorrido en orden como ejemplo)
preorder(root); // 从根结点开始遍历
preorder(TreeNode node)
if(node != null)
list.add(node.val);
preorder(node.left);
preorder(node.right);
Recorrido de grafos de primer orden en profundidad : ligeramente diferente de los árboles, los algoritmos de grafos necesitan determinar si un nodo ha sido visitado antes de recurrir, y su complejidad de tiempo es O ( V + E ) O(V+E)O ( V+mi )
visited[0...V-1] = false;
// 使用 for 循环保证遍历每个点,使得算法可以应对非联通图
for(int v = 0; v < V; v++)
if(!visited[v])
dfs(v);
dfs(int v)
visited[v] = true; // 标记为已访问
list.add(v);
for(int w: adj(v))
if(!visited[w])
dfs(w);
implementación java: GraphDFS.java
4.1 Ej: encontrar el componente conectado
Es decir, la solución contiene varios gráficos conectados.
visited[0...V-1] = -1;
ccount = 0; // 联通分量
for(v = 0; v < V; v++)
if(visited[v] == -1)
dfs(v, ccount);
ccount++;
dfs(v, ccid)
visited[v] = ccid;
list.add(v);
for(int w: adj(v))
if(visited[w] == -1)
dfs(w, ccid);
implementación java: CC.java
Encuentre si dos puntos son alcanzables : solo necesita juzgar de la siguiente manera
visited[v] == visited[w];
4.2 Ej: encontrar el camino entre dos puntos
(no necesariamente el más corto)
// pre[i] = j 表示存在路径 j->i
// pre[i] = -1 表示尚未访问,代替 visited[i] = false
pre[0...V-1] = -1;
s = 0; // 自定义的起始点
t = 5; // 自定义的终止点
pre[s] = s; // 将源头的源头设为自己
dfs(s);
// 返回值表示是否达到了目标点 t
boolean dfs(int v)
for(int w: adj(v))
if(visited[w] == -1)
pre[w] = v;
if(w == t) return true;
if(dfs(w)) return true;
return false;
==implementación de Java: Path.java==
4.3 Ej.: Detección de timbre
implementación java: CycleDetection.java
4.4 Ej.: Detección de gráfico bipartito
Los dos gráficos de la izquierda y la derecha que parecen completamente diferentes son en realidad iguales, pero la forma de la izquierda es obviamente un gráfico bipartito, mientras que la forma más ordinaria y aleatoria de la derecha no se puede juzgar intuitivamente.
Use DFS para la detección de gráficos bipartitos:
// -1: 未访问
// 0: 二分图的一侧
// 1: 二分图的另一侧
color[0...V-1] = -1;
color[0] = 0;
dfs(0);
// 返回值表示是否检测到了目标图不是二分图的证据
boolean dfs(int v)
for(int w: adj(v))
if(color[w] == -1)
color[w] = 1 - color[v]
if(dfs(w)) return true;
else if(color[w] == color[v])
return true
return false;
implementación de java: BipartitionDetection.java