数据结构–图(深度优先遍历和广度优先遍历)(Java)
<!– more –>
博客阐明
文章所波及的材料来自互联网整顿和集体总结,意在于集体学习和教训汇总,如有什么中央侵权,请分割自己删除,谢谢!
图的罕用概念
图是一种数据结构,其中结点能够具备零个或多个相邻元素。两个结点之间的连贯称为边。结点也能够称为顶点。
- 顶点 (vertex)
- 边 (edge)
- 门路
- 无向图
- 有向图
- 带权图
图的示意形式
图的示意形式有两种:二维数组示意(邻接矩阵);链表示意(邻接表)。
邻接矩阵
邻接矩阵是示意图形中顶点之间相邻关系的矩阵,对于 n 个顶点的图而言,矩阵是的 row 和 col 示意的是 1 ….n 个点。
邻接表
邻接矩阵须要为每个顶点都调配 n 个边的空间,其实有很多边都是不存在, 会造成空间的肯定损失
邻接表的实现只关怀存在的边,不关怀不存在的边。因而没有空间节约,邻接表由数组 + 链表组成
代码实现
package com.guizimo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
public class Graph {
private ArrayList<String> vertexList;
private int[][] edges;
private int numOfEdges;
private boolean[] isVisited;
public static void main(String[] args) {
int n = 8;
String Vertexs[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
Graph graph = new Graph(n);
for(String vertex: Vertexs) {graph.insertVertex(vertex);
}
// 插入图的节点
graph.insertEdge(0, 1, 1);
graph.insertEdge(0, 2, 1);
graph.insertEdge(1, 3, 1);
graph.insertEdge(1, 4, 1);
graph.insertEdge(3, 7, 1);
graph.insertEdge(4, 7, 1);
graph.insertEdge(2, 5, 1);
graph.insertEdge(2, 6, 1);
graph.insertEdge(5, 6, 1);
// 遍历图
graph.showGraph();
System.out.println(" 广度优先遍历
graph.dfs();
System.out.println(" 深度优先遍历
graph.bfs();}
public Graph(int n) {edges = new int[n][n];
vertexList = new ArrayList<String>(n);
numOfEdges = 0;
}
public int getFirstNeighbor(int index) {for(int j = 0; j < vertexList.size(); j++) {if(edges[index][j] > 0) {return j;}
}
return -1;
}
public int getNextNeighbor(int v1, int v2) {for(int j = v2 + 1; j < vertexList.size(); j++) {if(edges[v1][j] > 0) {return j;}
}
return -1;
}
// 深度优先遍历
private void dfs(boolean[] isVisited, int i) {System.out.print(getValueByIndex(i) + "->");
isVisited[i] = true;
int w = getFirstNeighbor(i);
while(w != -1) {if(!isVisited[w]) {dfs(isVisited, w);
}
w = getNextNeighbor(i, w);
}
}
public void dfs() {isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {if(!isVisited[i]) {dfs(isVisited, i);
}
}
}
// 广度优先遍历
private void bfs(boolean[] isVisited, int i) {
int u ;
int w ;
LinkedList queue = new LinkedList();
System.out.print(getValueByIndex(i) + "=>");
isVisited[i] = true;
queue.addLast(i);
while(!queue.isEmpty()) {u = (Integer)queue.removeFirst();
w = getFirstNeighbor(u);
while(w != -1) {if(!isVisited[w]) {System.out.print(getValueByIndex(w) + "=>");
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u, w);
}
}
}
public void bfs() {isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {if(!isVisited[i]) {bfs(isVisited, i);
}
}
}
public int getNumOfVertex() {return vertexList.size();
}
// 遍历
public void showGraph() {for(int[] link : edges) {System.err.println(Arrays.toString(link));
}
}
public int getNumOfEdges() {return numOfEdges;}
public String getValueByIndex(int i) {return vertexList.get(i);
}
public int getWeight(int v1, int v2) {return edges[v1][v2];
}
// 增加邻接矩阵
public void insertVertex(String vertex) {vertexList.add(vertex);
}
// 插入权值
public void insertEdge(int v1, int v2, int weight) {edges[v1][v2] = weight;
edges[v2][v1] = weight;
numOfEdges++;
}
}
图的深度优先搜寻 (Depth First Search)
深度优先遍历,从初始拜访结点登程,初始拜访结点可能有多个邻接结点,深度优先遍历的策略就是首先拜访第一个邻接结点,而后再以这个被拜访的邻接结点作为初始结点,拜访它的第一个邻接结点,能够这样了解:每次都在拜访完以后结点后首先拜访以后结点的第一个邻接结点
算法
- 拜访初始结点 v,并标记结点 v 为已拜访。
- 查找结点 v 的第一个邻接结点 w。
- 若 w 存在,则继续执行 4,如果 w 不存在,则回到第 1 步,将从 v 的下一个结点持续。
- 若 w 未被拜访,对 w 进行深度优先遍历递归(即把 w 当做另一个 v,而后进行步骤 123)。
- 查找结点 v 的 w 邻接结点的下一个邻接结点,转到步骤 3
代码
// 深度优先遍历
private void dfs(boolean[] isVisited, int i) {System.out.print(getValueByIndex(i) + "->");
isVisited[i] = true;
int w = getFirstNeighbor(i);
while(w != -1) {if(!isVisited[w]) {dfs(isVisited, w);
}
w = getNextNeighbor(i, w);
}
}
public void dfs() {isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {if(!isVisited[i]) {dfs(isVisited, i);
}
}
}
图的广度优先搜寻 (Broad First Search)
相似于一个分层搜寻的过程,广度优先遍历须要应用一个队列以放弃拜访过的结点的程序,以便按这个程序来拜访这些结点的邻接结点
算法
- 拜访初始结点 v 并标记结点 v 为已拜访。
- 结点 v 入队列
- 当队列非空时,继续执行,否则算法完结。
- 出队列,获得队头结点 u。
- 查找结点 u 的第一个邻接结点 w。
-
若结点 u 的邻接结点 w 不存在,则转到步骤 3;否则循环执行以下三个步骤:
- 若结点 w 尚未被拜访,则拜访结点 w 并标记为已拜访。
- 结点 w 入队列
- 查找结点 u 的继 w 邻接结点后的下一个邻接结点 w,转到步骤 6
代码
// 广度优先遍历
private void bfs(boolean[] isVisited, int i) {
int u ;
int w ;
LinkedList queue = new LinkedList();
System.out.print(getValueByIndex(i) + "=>");
isVisited[i] = true;
queue.addLast(i);
while(!queue.isEmpty()) {u = (Integer)queue.removeFirst();
w = getFirstNeighbor(u);
while(w != -1) {if(!isVisited[w]) {System.out.print(getValueByIndex(w) + "=>");
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u, w);
}
}
}
public void bfs() {isVisited = new boolean[vertexList.size()];
for(int i = 0; i < getNumOfVertex(); i++) {if(!isVisited[i]) {bfs(isVisited, i);
}
}
}
感激
尚硅谷
以及勤奋的本人,集体博客,GitHub