From c74f8293b9249cf879a97b8e41b3914461cc5599 Mon Sep 17 00:00:00 2001 From: krahets Date: Mon, 13 Feb 2023 16:20:08 +0800 Subject: [PATCH] Graph dev --- codes/java/chapter_graph/graph_traversal.java | 70 +++++++++++++++++++ docs/chapter_graph/graph_traversal.md | 31 ++++++++ docs/chapter_tree/binary_tree_traversal.md | 44 ++++++------ 3 files changed, 124 insertions(+), 21 deletions(-) create mode 100644 codes/java/chapter_graph/graph_traversal.java create mode 100644 docs/chapter_graph/graph_traversal.md diff --git a/codes/java/chapter_graph/graph_traversal.java b/codes/java/chapter_graph/graph_traversal.java new file mode 100644 index 00000000..3b152198 --- /dev/null +++ b/codes/java/chapter_graph/graph_traversal.java @@ -0,0 +1,70 @@ +/** + * File: graph_adjacency_list.java + * Created Time: 2023-02-12 + * Author: Krahets (krahets@163.com) + */ + +package chapter_graph; + +import java.util.*; + +public class graph_traversal { + /* 以顶点 vet 为起点,对图 graph 执行广度优先遍历 */ + // 采用 GraphAdjList 表示图,以方便获取指定结点的所有邻接结点 + static List graphBFS(GraphAdjList graph, Vertex startVet) { + // 顶点遍历序列 + List res = new ArrayList<>(); + // 用于记录顶点是否已被访问 + Set visited = new HashSet<>() {{ add(startVet); }}; + // 队列用于实现 BFS + Queue que = new LinkedList<>() {{ offer(startVet); }}; + // 循环直至访问完所有顶点 + while (!que.isEmpty()) { + Vertex vet = que.poll(); // 队首顶点出队 + res.add(vet); // 访问该顶点 + // 遍历该顶点的所有邻接顶点 + for (Vertex adjVet : graph.adjList.get(vet)) { + if (!visited.contains(adjVet)) { + que.offer(adjVet); // 只入队未访问的顶点 + visited.add(adjVet); // 标记该顶点已被访问 + } + } + } + // 返回顶点遍历序列 + return res; + } + + /* 输入值列表 vals ,返回顶点列表 vets */ + static Vertex[] valsToVets(int[] vals) { + Vertex[] vets = new Vertex[vals.length]; + for (int i = 0; i < vals.length; i++) { + vets[i] = new Vertex(vals[i]); + } + return vets; + } + + /* 输入顶点列表 vets ,返回值列表 vals */ + static List vetsToVals(List vets) { + List vals = new ArrayList<>(); + for (Vertex vet : vets) { + vals.add(vet.val); + } + return vals; + } + + public static void main(String[] args) { + /* 初始化无向图 */ + Vertex[] v = valsToVets(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + Vertex[][] edges = { { v[0], v[1] }, { v[0], v[3] }, { v[1], v[2] }, { v[1], v[4] }, + { v[2], v[5] }, { v[3], v[4] }, { v[3], v[6] }, { v[4], v[5] }, + { v[4], v[7] }, { v[5], v[8] }, { v[6], v[7] }, { v[7], v[8] }}; + GraphAdjList graph = new GraphAdjList(edges); + System.out.println("\n初始化后,图为"); + graph.print(); + + /* 广度优先遍历 BFS */ + List res = graphBFS(graph, v[0]); + System.out.println("\n广度优先遍历(BFS)顶点序列为"); + System.out.println(vetsToVals(res)); + } +} diff --git a/docs/chapter_graph/graph_traversal.md b/docs/chapter_graph/graph_traversal.md new file mode 100644 index 00000000..fccd5150 --- /dev/null +++ b/docs/chapter_graph/graph_traversal.md @@ -0,0 +1,31 @@ +--- +comments: true +--- + +# 图的遍历 + +与遍历树类似,遍历图也需要通过搜索算法来实现,并也可根据遍历顺序来分为「广度优先遍历 Breadth-First Traversal」和「深度优先遍历 Depth-First Travsersal」,简称分别为 BFS 和 DFS 。 + +!!! tip 「树」与「图」的关系 + + 本质上,可以把树看作是图的一种特例,即树是一种限制条件下的图。 + +## 广度优先遍历 + +广度优先遍历(BFS)代表一种优先遍历最近的顶点、一层层向外扩张的遍历方式。具体来看,从某个顶点出发,则优先遍历该顶点的所有邻接顶点,随后遍历下个顶点的所有邻接顶点,以此类推…… + +(图) + +BFS 常借助「队列」来实现,队列具有“先入先出”的性质,这与 BFS 的“由近及远”的遍历方式是异曲同工的。具体地,在每轮迭代中弹出队首顶点且访问之,并将该顶点的所有邻接顶点加入到队列尾部,直到所有顶点访问完成即可。 + +为了防止重复遍历顶点,我们需要借助一个 HashSet 来记录哪些结点已被访问,从而避免走“回头路”。 + +```java + +``` + + + +## 深度优先遍历 + +深度优先遍历(DFS)代表一种优先走到底,无路可走再回头的遍历方式。从某个顶点出发,首先不断地通过指针向下一个顶点遍历,直到走到头开始回溯,再继续走到底 + 回溯,以此类推…… \ No newline at end of file diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index 04b641d0..4267b71b 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -4,7 +4,9 @@ comments: true # 7.2. 二叉树遍历 -非线性数据结构的遍历操作比线性数据结构更加复杂,往往需要使用搜索算法来实现。常见的二叉树遍历方式有层序遍历、前序遍历、中序遍历、后序遍历。 +从物理结构角度看,树是一种基于链表的数据结构,因此遍历方式也是通过指针(即引用)逐个遍历结点。同时,树还是一种非线性数据结构,这导致遍历树比遍历链表更加复杂,需要使用搜索算法来实现。 + +常见的二叉树遍历方式有层序遍历、前序遍历、中序遍历、后序遍历。 ## 7.2.1. 层序遍历 @@ -102,9 +104,9 @@ comments: true ```java title="binary_tree_dfs.java" [class]{binary_tree_dfs}-[func]{preOrder} - + [class]{binary_tree_dfs}-[func]{inOrder} - + [class]{binary_tree_dfs}-[func]{postOrder} ``` @@ -112,9 +114,9 @@ comments: true ```cpp title="binary_tree_dfs.cpp" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -122,9 +124,9 @@ comments: true ```python title="binary_tree_dfs.py" [class]{}-[func]{pre_order} - + [class]{}-[func]{in_order} - + [class]{}-[func]{post_order} ``` @@ -132,9 +134,9 @@ comments: true ```go title="binary_tree_dfs.go" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -142,9 +144,9 @@ comments: true ```javascript title="binary_tree_dfs.js" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -152,9 +154,9 @@ comments: true ```typescript title="binary_tree_dfs.ts" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -162,9 +164,9 @@ comments: true ```c title="binary_tree_dfs.c" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -172,9 +174,9 @@ comments: true ```csharp title="binary_tree_dfs.cs" [class]{binary_tree_dfs}-[func]{preOrder} - + [class]{binary_tree_dfs}-[func]{inOrder} - + [class]{binary_tree_dfs}-[func]{postOrder} ``` @@ -182,9 +184,9 @@ comments: true ```swift title="binary_tree_dfs.swift" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ``` @@ -192,9 +194,9 @@ comments: true ```zig title="binary_tree_dfs.zig" [class]{}-[func]{preOrder} - + [class]{}-[func]{inOrder} - + [class]{}-[func]{postOrder} ```