1.图概念
- 顶点(vertex):图的元素我们就叫做顶点(vertex)
- 边(edge):一个顶点可以与任意其他顶点建立连接关系,这种建立的关系叫做边(edge)
- 度(degree):顶点相连接的边的条数叫做度(degree)
- 有向图:边有方向的图叫做有向图
- 无向图:边无方向的图叫无向图
- 带权图:每条边都有一个权重(weight),可以通过这个权重来表示 一些可度量的值 ,这样的图叫做带权图(weighted graph)
2.图的存储
存储可以采用数组或链表,数组采用邻接矩阵,链表采用邻接表
2.1 邻接矩阵存储
邻接矩阵(Adjacency Matrix)的底层是一个二维数组graph[row][col],row表示行,col表示列
优点:快,可以通过下标访问
缺点:浪费空间,用二维数组实现确开辟了多余空间维护与其他顶点的关系
2.1.1 无向图
行列下标0-5表示A-F【也可以行列下标1-6表示A-F,下标从[1][1]开始,直观但是浪费了一行一列空间】
如graph[1][4]=graph[B][E]=0表示B到E没边
如graph[1][3]=graph[B][D]=1表示B到D有边
分析:B实际只与A和D有关系,用二维数组实现确开辟了多余空间维护与其他顶点的关系
2.1.2 有向图
graph[0][1]=1表示1指向2,graph[1][0]=0表示2没指向1
graph[1][2]=1,graph[2][1]=1,表示23之间相互指向
2.1.3 带权图
数组中就存储相应的权重
2.1.4 代码实现
package datastructure.graph;
import java.util.*;
/**
* 图
*
* @author zw
* @create 2023-04-17 0:22
*/
public class Graph<T> {
// 是否有方向,默认无,有向图顶点关系都双向指向时与无向图没发区分,需要通过属性区分
private boolean hasDirection = false;
private Map<T, Integer> edgesMap; // 保存顶点与矩阵下标关系
private Map<Integer, T> indexEdgesMap; // 保存顶点与矩阵下标关系
private List<T> vertexList;//存储点的链表
private int[][] edges;//邻接矩阵,用来存储边,值是权值
private int numOfEdges;//边的数目
public Graph(int n, boolean hasDirection) {
this(n);
this.hasDirection = hasDirection;
}
public Graph(int n) {
//初始化矩阵,一维数组,和边的数目
edges = new int[n][n];
vertexList = new ArrayList(n);
edgesMap = new HashMap<>();
indexEdgesMap = new HashMap<>();
numOfEdges = 0;
}
//得到结点的个数
public int getNumOfVertex() {
return vertexList.size();
}
//得到边的数目
public int getNumOfEdges() {
return numOfEdges;
}
//返回结点i的数据
public Object getValueByIndex(int i) {
return vertexList.get(i);
}
//返回v1,v2的权值
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
//返回v1,v2的权值
public int getWeight(T v1, T v2) {
return edges[edgesMap.get(v1)][edgesMap.get(v2)];
}
//插入结点
public void insertVertex(T vertex) {
vertexList.add(vertex);
Integer max = edgesMap.values().stream().max(Comparator.comparing(x -> x)).orElse(-1);
edgesMap.put(vertex, max + 1);
}
//删除结点
public void deleteVertex(T vertex) {
int size = vertexList.size();
vertexList.remove(vertex);
Integer vertexIndex = edgesMap.get(vertex);
edgesMap.remove(vertex);
// 该点行列全变为0,回收所有边
for (int col = 0; col < size; col++) {
edges[vertexIndex][col] = 0;
}
for (int row = 0; row < size; row++) {
edges[row][vertexIndex] = 0;
}
}
//插入带权边
public void insertEdge(int v1, int v2, int weight) {
edges[v1][v2] = weight; // 有方向
if (!hasDirection) {
edges[v2][v1] = weight; // 无方向
}
numOfEdges++;
}
//插入带权边
public void insertEdge(T v1, T v2, int weight) {
edges[edgesMap.get(v1)][edgesMap.get(v2)] = weight; // 有方向
if (!hasDirection) {
edges[edgesMap.get(v2)][edgesMap.get(v1)] = weight; // 无方向
}
numOfEdges++;
}
//插入不带权边
public void insertEdge(int v1, int v2) {
edges[v1][v2] = 1;
if (!hasDirection) {
edges[v2][v1] = 1; // 无方向
}
numOfEdges++;
}
//插入不带权边
public void insertEdge(T v1, T v2) {
edges[edgesMap.get(v1)][edgesMap.get(v2)] = 1; // 有方向
if (!hasDirection) {
edges[edgesMap.get(v2)][edgesMap.get(v1)] = 1; // 无方向
}
numOfEdges++;
}
//删除边
public void deleteEdge(int v1, int v2) {
edges[v1][v2] = 0;
if (!hasDirection) {
edges[v2][v1] = 0; // 无方向
}
numOfEdges--;
}
//删除带权边
public void deleteEdge(T v1, T v2) {
edges[edgesMap.get(v1)][edgesMap.get(v2)] = 0; // 有方向
if (!hasDirection) {
edges[edgesMap.get(v2)][edgesMap.get(v1)] = 0; // 无方向
}
numOfEdges--;
}
}
测试用例
private void print() {
for (int[] rows : edges) {
System.out.println(Arrays.toString(rows));
}
}
public static void main(String[] args) {
String[] nodes = {"A", "B", "C", "D", "E", "F"};
String[][] weightedEdges = {
{"A", "B","2"}, {"A", "C","2"}, {"A", "D","2"},
{"B", "D","3"},
{"C", "E","4"}, {"C", "F","4"},
{"D", "E","5"}, {"D", "F","5"},
{"E", "F","6"},};
System.out.println("---------无向图------------");
Graph<String> graph = new Graph<String>(6);
for (String node : nodes) {
graph.insertVertex(node);
}
for (String[] edge : weightedEdges) {
graph.insertEdge(edge[0], edge[1]);
}
graph.print();
System.out.println("---------有向图------------");
Graph<String> directedGraph = new Graph<String>(6,true);
for (String node : nodes) {
directedGraph.insertVertex(node);
}
for (String[] edge : weightedEdges) {
directedGraph.insertEdge(edge[0], edge[1]);
}
directedGraph.print();
System.out.println("---------带权有向图------------");
Graph<String> weightedGraph = new Graph<String>(6,true);
for (String node : nodes) {
weightedGraph.insertVertex(node);
}
for (String[] edge : weightedEdges) {
weightedGraph.insertEdge(edge[0], edge[1],Integer.valueOf(edge[2]));
}
weightedGraph.print();
}
运行结果
---------无向图------------
[0, 1, 1, 1, 0, 0]
[1, 0, 0, 1, 0, 0]
[1, 0, 0, 0, 1, 1]
[1, 1, 0, 0, 1, 1]
[0, 0, 1, 1, 0, 1]
[0, 0, 1, 1, 1, 0]
---------有向图------------
[0, 1, 1, 1, 0, 0]
[0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 1]
[0, 0, 0, 0, 1, 1]
[0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 0]
---------带权有向图------------
[0, 2, 2, 2, 0, 0]
[0, 0, 0, 3, 0, 0]
[0, 0, 0, 0, 4, 4]
[0, 0, 0, 0, 5, 5]
[0, 0, 0, 0, 0, 6]
[0, 0, 0, 0, 0, 0]
2.2 邻接表存储
优点:节省空间
缺点:慢
稀疏图:顶点很多,但每个顶点的边并不多。邻接矩阵的存储方法就更加浪费空间,邻接表解决
数组+链表进行存储,数组中元素表示出发的点,链表表示能到的所有点
2.2.1 代码实现
顶点
class Vertex<T> {
String name;//顶点唯一标识
T data; // 携带数据
boolean visit; // 是否访问过,默认false
Edge next;//从该定点出发的边
public Vertex(String name, Edge edge, T data) {
this.name = name;
this.next = edge;
this.data = data;
}
@Override
public String toString() {
return name;
}
}
边
class Edge {
String name;//指向下一个顶点
int weight;//权重
boolean visit; // 是否访问过,默认false
Edge next;//指向的下一个边
public Edge(String name, int weight, Edge next) {
this.name = name;
this.weight = weight;
this.next = next;
}
}
图
public class Graph<T> {
// 存储:数组+链表 也就是map
Map<String, Vertex> vertexsMap = new HashMap<>();
/**
* 添加顶点
*
* @param name 顶点名称
*/
public void insertVertex(String name) {
Vertex vertex = new Vertex(name, null, null);
vertexsMap.put(name, vertex);
}
public void insertVertex(String name, T data) {
Vertex vertex = new Vertex(name, null, data);
vertexsMap.put(name, vertex);
}
/**
* 删除顶点
*
* @param deleteVertexName 顶点名称
*/
public void deleteVertex(String deleteVertexName) {
vertexsMap.remove(deleteVertexName);
// 删除其他顶点到删除顶点的边
vertexsMap.forEach((startVertexName, vertex) -> {
Edge currEdge = vertex.next;
if (currEdge != null && currEdge.name.equals(deleteVertexName)) {
vertex.next = currEdge.next;
} else {
while (currEdge != null) {
Edge next = currEdge.next;
if (next != null && next.name.equals(deleteVertexName)) {
currEdge.next = next.next;
break;
}
currEdge = currEdge.next;
}
}
});
}
/**
* 插入边
*
* @param start 开始顶点名称
* @param end 结束顶点名称
* @param weight 权重
*/
public void insertEdge(String start, String end, int weight) throws Exception {
//现获取开始顶点
Vertex startVertex = vertexsMap.get(start);
Vertex endVertex = vertexsMap.get(end);
if (startVertex == null || endVertex == null) {
throw new Exception("起止顶点可能不存在");
}
Edge edge = new Edge(end, weight, null);
if (startVertex.next == null) {
startVertex.next = edge;
} else {
//如果不为null 寻找节点的next==null的位置,挂上这个边
Edge lastEdge = startVertex.next;
while (lastEdge.next != null) {
lastEdge = lastEdge.next;
}
lastEdge.next = edge;
}
}
/**
* 删除边
*
* @param startVertexName 起始顶点名
* @param endVertexName 结束顶点名
* @throws Exception
*/
public void deleteEdge(String startVertexName, String endVertexName) throws Exception {
Vertex vertex = vertexsMap.get(startVertexName);
if (vertex == null) {
throw new Exception(startVertexName + "顶点不存在");
}
Edge currEdge = vertex.next;
if (currEdge.name.equals(endVertexName)) {
vertex.next = currEdge.next;
} else {
while (currEdge != null) {
Edge next = currEdge.next;
if (next != null && next.name.equals(endVertexName)) {
currEdge.next = next.next;
break;
}
currEdge = currEdge.next;
}
}
}
public void print() {
vertexsMap.forEach((vertexName, vertex) -> {
Edge edge = vertex.next;
while (edge != null) {
System.out.println(vertexName + "指向" + edge.name + " 权重" + edge.weight);
edge = edge.next;
}
});
}
}
测试用例
public static void main(String[] args) throws Exception {
Graph graph = new Graph();
String[] vertexs = {"A", "B", "C", "D", "E", "F"};
for (String vertex : vertexs) {
graph.insertVertex(vertex);
}
String[][] weightedEdges = {
{"C", "A", "1"},
{"F", "C", "2"},
{"A", "B", "4"},
{"E", "B", "2"},
{"A", "D", "5"},
{"D", "F", "4"},
{"D", "E", "3"}};
for (String[] weightedEdge : weightedEdges) {
graph.insertEdge(weightedEdge[0], weightedEdge[1], Integer.valueOf(weightedEdge[2]));
}
graph.print();
System.out.println("-----删除C-----");
graph.deleteVertex("C");
graph.print();
System.out.println("-----删除A到B方向的边-----");
graph.deleteEdge("A", "B");
graph.print();
}
运行结果
A指向B 权重4
A指向D 权重5
C指向A 权重1
D指向F 权重4
D指向E 权重3
E指向B 权重2
F指向C 权重2
-----删除C-----
A指向B 权重4
A指向D 权重5
D指向F 权重4
D指向E 权重3
E指向B 权重2
-----删除A到C方向的边-----
A指向D 权重5
D指向F 权重4
D指向E 权重3
E指向B 权重2
3. 图的遍历
- 从指定的顶点(称为初始点)出发
- 按照某种搜索方法沿着图的边访问图中的所有顶点,每个顶点仅被访问一次
- 遍历过程中得到的顶点序列称为图遍历序列
图的遍历策略:
- 深度优先搜索 (DFS,Depth First Search )
从起点出发,从规定的方向中选择其中一个不断地向前走,直到无法继续为止,然后回溯尝试另外一种方向,直到最后走到终点。就像走迷宫一样,尽量往深处走
DFS 解决的是连通性的问题
即,给定两个点,一个是起始点,一个是终点,判断是不是有一条路径能从起点连接到终点。起点和终点,也可以指的是某种起始状态和最终的状态。问题的要求并不在乎路径是长还是短,只在乎有还是没有。
- 广度优先搜索(BFS,Breadth First Search )
3.1 广度优先遍历
3.1.1 邻接矩阵广度优先遍历
- 将起始顶点放入队列
- 出队并记录
- 获取该顶点能到的所有顶点(从小到大排序),放入队列
- 循环2、3步骤,直到队列没数据
从指定顶点广度优先遍历
/**
* 从指定点广度优先遍历
*
* @param vertex 起始顶点
* @param mark 记录边是否走过
* @param vertexMap 记录顶点是否走过
* @return
*/
private String bfs(T vertex, boolean[][] mark, Map<T, Boolean> vertexMap) {
if (mark == null) {
mark = new boolean[edges.length][edges.length];
}
if (vertexMap == null) {
vertexMap = vertexList.stream().collect(Collectors.toMap(item -> item, item -> Boolean.FALSE));
}
StringBuffer sb = new StringBuffer();
LinkedListQueue<T> queue = new LinkedListQueue<T>(16);
queue.add(vertex);
while (!queue.isEmpty()) {
T poll = queue.poll();
sb.append(poll).append(" ");
Integer edgeIndex = edgesMap.get(poll);
// 获取该顶点指向的顶点
for (int col = 0; col < edges.length; col++) { // 这就是顺序遍历了
int value = edges[edgeIndex][col];
T toVertex = indexEdgesMap.get(col);
if (value > 0 && !mark[edgeIndex][col] && !vertexMap.get(toVertex)) {
vertexMap.put(toVertex, true);
mark[edgeIndex][col] = true; // 标记访问记录
if (!hasDirection) {
mark[col][edgeIndex] = true; //无向图标记量变
}
queue.add(toVertex);
}
}
}
return sb.toString();
}
测试用例
public static void main(String[] args) {
String[] vertexs = {"A", "B", "C", "D", "E", "F", "G", "H"};
String[][] edges = {
{"A", "B", "2"}, {"A", "D", "2"}, {"A", "G", "2"},
{"B", "E", "3"}, {"B", "F", "3"},
{"C", "F", "4"}, {"C", "H", "4"},
{"D", "A", "5"}, {"D", "F", "5"},
{"E", "B", "6"}, {"E", "G", "6"},
{"F", "B", "6"}, {"F", "D", "6"}, {"F", "C", "6"},
{"G", "A", "6"}, {"G", "E", "6"},
{"H", "C", "6"},
};
Graph<String> dfsGraph = new Graph<String>(8);
for (String node : vertexs) {
dfsGraph.insertVertex(node);
}
for (String[] edge : edges) {
dfsGraph.insertEdge(edge[0], edge[1]);
}
dfsGraph.print();
System.out.println("---------广度优先遍历------------");
System.out.println(dfsGraph.bfs("A", null, null));
}
运行结果
[0, 1, 0, 1, 0, 0, 1, 0]
[1, 0, 0, 0, 1, 1, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 1]
[1, 0, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 0, 0, 0, 1, 0]
[0, 1, 1, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
---------广度优先遍历------------
A B D G E F C H
3.1.2 邻接表广度优先遍历
/**
* 广度优先遍历
*
* @param startVertexName 搜索起始位置
*/
private void bfs(String startVertexName) {
MyPriorityQueue<Vertex> priorityQueue = new MyPriorityQueue<Vertex>((o1, o2) -> o1.name.compareTo(o2.name));
LinkedListQueue<Vertex> queue = new LinkedListQueue<Vertex>(16); // 辅助队列
// 获取顶点
Vertex vertex = vertexsMap.get(startVertexName);
vertex.visit = true; // 标记顶点
queue.add(vertex); // 放入队列中
while (!queue.isEmpty()) {
Vertex currVertex = queue.poll();
System.out.print(currVertex.name + " ");
Edge currEdge = currVertex.next;
// 将当前顶点指向的订单放入队列
while (currEdge != null && !currEdge.visit) {
currEdge.visit = true; // 记录访问
Vertex nextVertex = vertexsMap.get(currEdge.name);
priorityQueue.offer(nextVertex);
currEdge = currEdge.next;
}
while (!priorityQueue.isEmpty()) {
Vertex poll = priorityQueue.poll();
if (!poll.visit) {
poll.visit = true; // 标记顶点
queue.add(poll);
}
}
}
}
测试用例
public static void main(String[] args) throws Exception {
AdjacencyList bfsGraph = new AdjacencyList();
vertexs = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
weightedEdges = new String[][]{
{"A", "B", "2"}, {"A", "D", "2"}, {"A", "G", "2"},
{"B", "E", "3"}, {"B", "F", "3"},
{"C", "F", "4"}, {"C", "H", "4"},
{"D", "A", "5"}, {"D", "F", "5"},
{"E", "B", "6"}, {"E", "G", "6"},
{"F", "B", "6"}, {"F", "D", "6"}, {"F", "C", "6"},
{"G", "A", "6"}, {"G", "E", "6"},
{"H", "C", "6"}
};
for (String vertex : vertexs) {
bfsGraph.insertVertex(vertex);
}
for (String[] weightedEdge : weightedEdges) {
bfsGraph.insertEdge(weightedEdge[0], weightedEdge[1], Integer.valueOf(weightedEdge[2]));
}
System.out.println("广度优先遍历");
bfsGraph.bfs("A");
}
运行结果
广度优先遍历
A B D G E F C H
3.2 深度优先遍历
3.2.1 邻接表深度优先遍历
/**
* 深度优先遍历,思路:
* 1、处理起始顶,放入栈中
* 2、获取下一个未访问的顶,放入栈中
* 3、获取下一个未访问的顶为null说明访问到最深处
* 4、此时弹栈,循环2和3
*
* @param startVertexName 起始顶点
*/
private String dfs(String startVertexName) {
StringBuffer sb = new StringBuffer();
LinkedListStack<Vertex> stack = new LinkedListStack<>();// 辅助栈
Vertex vertex = vertexsMap.get(startVertexName); // 获取顶点
stack.push(vertex); // 放入栈中
vertex.visit = true; // 标记顶点
sb.append(vertex.name).append(" ");
Edge currEdge = vertex.next;
Vertex currVertex = currEdge == null ? null : vertexsMap.get(currEdge.name);
// 深度优先遍历
while (currVertex != null) {
if (!currVertex.visit) {
currVertex.visit = true;
sb.append(currVertex.name).append(" ");
stack.push(currVertex);
System.out.println("当前遍历顺序:"+sb.toString());
System.out.println("当前辅助栈:"+stack.toString());
currVertex = getFirstNoVisitVertex(currVertex);
while (currVertex == null) { // 深度到头了,需要回溯
Vertex visitVertex = stack.pop();
System.out.println("弹栈:"+stack.toString());
if (visitVertex == null) break; // 已访问顶点全部回溯了
currVertex = getFirstNoVisitVertex(visitVertex);
}
}
}
return sb.toString();
}
/**
* 获取下个未访问的顶点
*
* @param vertex
* @return
*/
private Vertex getFirstNoVisitVertex(Vertex vertex) {
// 辅助优先队列,确定顺序,用于验证结果
MyPriorityQueue<Vertex> priorityQueue = new MyPriorityQueue<Vertex>((o1, o2) -> o1.name.compareTo(o2.name));
if (vertex == null) return null;
Edge edge = vertex.next;
while (edge != null) {
Vertex nextVertex = vertexsMap.get(edge.name);
if (!nextVertex.visit) {
priorityQueue.offer(nextVertex);
//return nextVertex;
}
edge = edge.next;
}
if (!priorityQueue.isEmpty()) return priorityQueue.poll();// 弹出排序后的
return null;
}
测试用例
AdjacencyList bfsGraph = new AdjacencyList();
vertexs = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
weightedEdges = new String[][]{
{"A", "B", "2"}, {"A", "D", "2"}, {"A", "G", "2"},
{"B", "E", "3"}, {"B", "F", "3"},
{"C", "F", "4"}, {"C", "H", "4"},
{"D", "A", "5"}, {"D", "F", "5"},
{"E", "B", "6"}, {"E", "G", "6"},
{"F", "B", "6"}, {"F", "D", "6"}, {"F", "C", "6"},
{"G", "A", "6"}, {"G", "E", "6"},
{"H", "C", "6"}
};
for (String vertex : vertexs) {
bfsGraph.insertVertex(vertex);
}
for (String[] weightedEdge : weightedEdges) {
bfsGraph.insertEdge(weightedEdge[0], weightedEdge[1], Integer.valueOf(weightedEdge[2]));
}
String dfsResult = bfsGraph.dfs("A");
System.out.println("深度优先遍历:"+dfsResult);
运行结果
当前遍历顺序:A B
当前辅助栈:[B,A]
当前遍历顺序:A B E
当前辅助栈:[E,B,A]
当前遍历顺序:A B E G
当前辅助栈:[G,E,B,A]
弹栈:[E,B,A]
弹栈:[B,A]
弹栈:[A]
当前遍历顺序:A B E G F
当前辅助栈:[F,A]
当前遍历顺序:A B E G F C
当前辅助栈:[C,F,A]
当前遍历顺序:A B E G F C H
当前辅助栈:[H,C,F,A]
弹栈:[C,F,A]
弹栈:[F,A]
弹栈:[A]
当前遍历顺序:A B E G F C H D
当前辅助栈:[D,A]
弹栈:[A]
弹栈:[]
弹栈:[]
深度优先遍历:A B E G F C H D
3.2.2 邻接矩阵深度优先遍历
/**
* 深度优先遍历
*/
public void dfs_cycle() {
Map<T, Boolean> vertexMap = vertexList.stream().collect(Collectors.toMap(item -> item, item -> Boolean.FALSE));
// 遍历所有的节点,进行dfs
for (int row = 0; row < getNumOfVertex(); row++) {
T vertex = indexEdgesMap.get(row);
if (!vertexMap.get(vertex)) {
dfs_cycle(vertex, vertexMap);
}
}
}
/**
* 深度优先遍历
*
* @param vertex
* @param vertexMap
*/
private void dfs_cycle(T vertex, Map<T, Boolean> vertexMap){
// 输出访问节点
System.out.print(vertex + " ");
// 将该节点设置为已经访问
vertexMap.put(vertex,true);
// 查找节点i的第一个领结节点w
T toVertex = getFirstNextXertex(vertex);
//如果存在邻接节点
while (toVertex != null) {
//如果这个节点没有被访问;
if (!vertexMap.get(toVertex)) {
dfs_cycle(toVertex, vertexMap);
}
// 如果w节点应景访问了
toVertex = getNextXertex(vertex, toVertex);
}
}
/**
* 查找第一个连通的顶点
* @param vertex
* @return
*/
private T getFirstNextXertex(T vertex){
Integer edgeIndex = edgesMap.get(vertex);
for (int col = 0; col < edges.length; col++) {
int value = edges[edgeIndex][col];
T toVertex = indexEdgesMap.get(col);
if(value>0) return toVertex;
}
return null;
}
/**
*
* @param vertex 开始顶点
* @param findStartVertex 查找起始位置
* @return 下个顶点下标
*/
private T getNextXertex(T vertex,T findStartVertex){
Integer row = edgesMap.get(vertex);
Integer indStartCol = edgesMap.get(findStartVertex);
for (int col = indStartCol+1; col < edges.length; col++) {
int value = edges[row][col];
T toVertex = indexEdgesMap.get(col);
if(value>0) return toVertex;
}
return null;
}
测试用例
public static void main(String[] args) {
System.out.println("---------深度优先遍历------------");
String[] vertexs = {"A", "B", "C", "D", "E", "F", "G", "H"};
String[][] edges = {
{"A", "B", "2"}, {"A", "D", "2"}, {"A", "G", "2"},
{"B", "E", "3"}, {"B", "F", "3"},
{"C", "F", "4"}, {"C", "H", "4"},
{"D", "A", "5"}, {"D", "F", "5"},
{"E", "B", "6"}, {"E", "G", "6"},
{"F", "B", "6"}, {"F", "D", "6"}, {"F", "C", "6"},
{"G", "A", "6"}, {"G", "E", "6"},
{"H", "C", "6"},
};
Graph<String> dfsGraph = new Graph<String>(8);
for (String node : vertexs) {
dfsGraph.insertVertex(node);
}
for (String[] edge : edges) {
dfsGraph.insertEdge(edge[0], edge[1]);
}
dfsGraph.print();
dfsGraph.dfs_cycle();
}
运行结果
---------深度优先遍历------------
[0, 1, 0, 1, 0, 0, 1, 0]
[1, 0, 0, 0, 1, 1, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 1]
[1, 0, 0, 0, 0, 1, 0, 0]
[0, 1, 0, 0, 0, 0, 1, 0]
[0, 1, 1, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0]
A B E G F C H D