图数据结构
两种表示方式
- 邻接矩阵
- 优点:简单直观;方便查找任一顶点的所有邻接点;方便计算顶点的度;方便判断任意两个顶点是否存在边;
- 缺点:常采用二维数组稀疏存储,相对浪费空间;查找所有边相对耗时;
- 邻接表
- 优点:简单直观;方便查找任一顶点的所有邻接点;方便计算顶点的度;
- 缺点:常采用链表数组存储,空间利用率高;不便于判断任意两个顶点是否存在边;
邻接表
图:
图的邻接表表示:
广度优先搜索示意图:
深度优先搜索示意图:
JAVA的一种实现示例:
public class GraphStruct {
/**
* 图节点数
*/
private int vertexNum;
/**
* 无向图邻接表表示
*
* 顶点 0 --> 1 --> 2
* 顶点 1 --> 0 --> 2 --> 3
* 顶点 2 --> 3
* 顶点 3 --> 2
*
*/
private LinkedList<Integer>[] graph;
public GraphStruct(int vertexNum) {
this.vertexNum = vertexNum;
graph = new LinkedList[vertexNum];
for (int i = 0; i < this.vertexNum; i++) {
graph[i] = new LinkedList<>();
}
}
/**
* 添加边
*
* 无向图邻接表
*/
public GraphStruct addEdge(int start, int end) {
graph[start].add(end);
graph[end].add(start);
return this;
}
/**
* 广度优先搜索
*/
public int[] breadthFirstSearch() {
//逆向搜索路径
//reversedPath[j] = i, 表示路径 i --> j
int[] reversedPath = new int[this.vertexNum];
Arrays.fill(reversedPath, -1);
//记录已访问节点
boolean[] visited = new boolean[this.vertexNum];
//记录将要访问的节点
Queue<Integer> visiting = new LinkedList<>();
//从第0个节点访问所有层
int startNode = 0;
visiting.add(startNode);
visited[startNode] = true;
while (visiting.size() > 0) {
int visitingNode = visiting.poll();
//第一层开始访问,并将当前层已访问节点添加至将访问列表
graph[visitingNode].forEach(layerNode -> {
if (!visited[layerNode]) {
reversedPath[layerNode] = visitingNode;
visited[layerNode] = true;
visiting.add(layerNode);
}
});
}
return reversedPath;
}
/**
* 深度优先搜索
*/
public int[] depthFirstSearch() {
int[] reversedPath = new int[this.vertexNum];
Arrays.fill(reversedPath, -1);
boolean[] visited = new boolean[this.vertexNum];
recurDfs(0, reversedPath, visited);
return reversedPath;
}
/**
* 递归访问1至n层
*
* @param startNode
* @param prePath
* @param visited
*/
public void recurDfs(int startNode, int[] prePath, boolean[] visited) {
visited[startNode] = true;
LinkedList<Integer> visitingDeepLayer = graph[startNode];
for (int i = 0; i < visitingDeepLayer.size(); i ++) {
int deepLayerNode;
if (!visited[deepLayerNode = visitingDeepLayer.get(i)]) {
prePath[deepLayerNode] = startNode;
recurDfs(deepLayerNode, prePath, visited);
}
}
}
/**
* 打印搜索路径
*/
public void printPath(int[] reversedPath, int node) {
if (node < 0) return;
int pre = reversedPath[node];
printPath(reversedPath, pre);
System.out.print("->" + node);
}
/**
* 构建测试图-邻接表
*/
private static GraphStruct buildTest(GraphStruct gs) {
gs.addEdge(0, 1).addEdge(0, 2).addEdge(0, 3)
.addEdge(1, 4)
.addEdge(2, 4).addEdge(2, 5)
.addEdge(3, 5).addEdge(3, 6)
.addEdge(4, 7)
.addEdge(5, 7)
.addEdge(6, 7);
return gs;
}
}