在IT领域,图数据结构是计算机科学中的一个关键概念,用于表示对象之间的关系。图由顶点(或节点)和边组成,其中顶点代表实体,而边则表示这些实体之间的连接。根据遍历方式的不同,图的遍历可以分为深度优先遍历(DFS)和广度优先遍历(BFS)。本文将深入探讨这两种遍历方法,并提供其在Java中的实现。 ### 图的深度优先遍历(DFS) 深度优先遍历是一种递归地访问图中的所有顶点的方法,它首先访问一个顶点,然后沿着任意一条路径尽可能深地访问该顶点的所有子节点,直到到达一个没有子节点的顶点,此时回溯到上一个顶点并继续访问未被访问的子节点,直至所有顶点都被访问。 #### Java实现 在Java中,DFS可以通过递归函数来实现。下面是一个简化的示例代码: ```java void dfs(int vertex, boolean[] visited) { visited[vertex] = true; System.out.print(vertex + " "); for (Edge edge : getAdjacents(vertex)) { int adjVertex = toVertex(edge); if (!visited[adjVertex]) { dfs(adjVertex, visited); } } } void deepFirstTravel() { boolean[] visited = new boolean[vertexesNum()]; for (int i = 0; i < vertexesNum(); i++) { if (!visited[i]) { dfs(i, visited); } } } ``` 在这个实现中,`dfs`函数接收一个顶点和一个布尔数组作为参数,布尔数组用于标记顶点是否已被访问。`getAdjacents`函数返回与给定顶点相邻的所有顶点。 ### 图的广度优先遍历(BFS) 广度优先遍历是一种逐层访问图中顶点的方法,从根节点开始,先访问所有直接相连的顶点,然后再访问它们直接相连的顶点,依此类推,直到图中的所有顶点都被访问。 #### Java实现 BFS通常使用队列数据结构来实现,确保按层次顺序访问顶点。 ```java void bfs(int root) { Queue<Integer> queue = new LinkedList<>(); boolean[] visited = new boolean[vertexesNum()]; visited[root] = true; queue.add(root); while (!queue.isEmpty()) { int vertex = queue.poll(); System.out.print(vertex + " "); for (Edge edge : getAdjacents(vertex)) { int adjVertex = toVertex(edge); if (!visited[adjVertex]) { visited[adjVertex] = true; queue.add(adjVertex); } } } } void breathFirstTravel() { for (int i = 0; i < vertexesNum(); i++) { if (!visited[i]) { bfs(i); } } } ``` 在这个实现中,`bfs`函数使用一个队列来保存待访问的顶点,并用一个布尔数组来跟踪每个顶点的访问状态。每次从队列中取出一个顶点,访问它的所有邻接顶点,并将未访问过的邻接顶点添加到队列中。 ### 总结 图的深度优先遍历和广度优先遍历是探索图结构的两种基本方法,它们各有优势。DFS适合查找路径或进行拓扑排序,而BFS则更适合寻找最短路径或检查连通性。在Java中,通过适当的递归或迭代算法结合数据结构(如栈或队列),我们可以有效地实现这两种遍历方法,从而在各种图形应用中解决问题。
图G是由顶点的有穷集合,以及顶点之间的关系组成,顶点的集合记为V,顶点之间的关系构成边的集合E
G=(V,E).
说一条边从v1,连接到v2,那么有v1Ev2(E是V上的一个关系)《=》<v1,v2>∈E.
图有有向图,无向图之分,无向图的一条边相当于有向图的中两条边,即如果无向图的顶点v1和v2之间有一条边
,那么既有从v1连接到v2的边,也有从v2连接到v1的边,<v1,v2>∈E 并且<v2,v1>∈E,而有向图是严格区分方向的。
一般图的存储有两种方式
1)相邻矩阵,用一个矩阵来保持边的情况,<v1,v2>∈E则Matrix[v1][v2]=Weight.
2)邻接表,需要保存一个顺序存储的顶点表和每个顶点上的边的链接表。
这里的实现采用第二种方案,另外图又复杂图,简单图之分,复杂图可能在两点之间同一个方向有多条边,我们考虑的都是无环简单图,无环简单图是指顶点没有自己指向自己的边的简单图,即任取vi属于V => <vi,vi>不属于E并且没有重复边。
我们先给出图的ADT:
package algorithms.graph;
public interface Graph {
//mark
public static interface Edge{
public int getWeight();
}
int vertexesNum();
int edgeNum();
boolean isEdge(Edge edge);
void setEdge(int from,int to, int weight);
Edge firstEdge(int vertex);
int toVertex(Edge edge);
int fromVertex(Edge edge);
String getVertexLabel(int vertex);
void assignLabels(String[] labels);
void deepFirstTravel(GraphVisitor visitor);
void breathFirstTravel(GraphVisitor visitor);
}
其中的方法大多数比较一目了然,
其中
1)Edge firstEdge(int vertex)返回指定节点的边的链表里存的第一条边
2)Edge nextEdge(Edge edge),顺着边链表返回下一条边
3)fromVertex,toVertex很简单返回该边的起始顶点和终结顶点
4)getVertexLabel返回该定点对应的标号,assignLabels给所有顶点标上号
GraphVisitor是一个很简单的接口:
package algorithms.graph;
public interface GraphVisitor {
void visit(Graph g,int vertex);
}
OK,下面是该部分实现:
剩余12页未读,继续阅读
- 粉丝: 1
- 资源: 40
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
- 1
- 2
- 3
- 4
- 5
前往页