图的实现方式主要用到矩阵或链表,这里用的矩阵;
图的深度优先搜索就是一条路径一条路径的往完了走,需要用到栈;而广度优先搜索就是一层一层的搜索,需要用到队列;
这个是两种遍历方式都会用到的表示图节点的代码:
/**
* @ClassName Node
* @Description 图节点
* @Author lzq
* @Date 2019/6/19 04:39
* @Version 1.0
**/
public class Node {
public char label; //存放的数据
public boolean wasVisited; //记录有无被访问过
public Node(char label) {
this.label = label;
this.wasVisited = false;
}
}
图的深度优先搜索
代码:
import java.util.Stack;
/**
* @ClassName Graph
* @Description 图的深度优先搜索
* @Author lzq
* @Date 2019/6/19 04:41
* @Version 1.0
**/
public class Graph {
private final int MAX_VERTS = 20; //表示一个图节点能连接的最大定点数
private Node[] nodeList; //顶点数组
private int[][] adjMat; //邻接矩阵,用来存方节点之间关系的
private int nNode; //当前顶点数量
private Stack<Integer> stack; //深度优先遍历需要用到
public Graph() {
nodeList = new Node[MAX_VERTS];
adjMat = new int[MAX_VERTS][MAX_VERTS];
nNode = 0;
for (int i = 0; i < MAX_VERTS; i++) {
for (int j = 0; j < MAX_VERTS; j++) {
adjMat[i][j] = 0;
}
}
stack = new Stack<>();
}
/**
* 添加节点
* @param lab
*/
public void addNode(char lab) {
nodeList[nNode++] = new Node(lab);
}
/**
* 添加节点直接的边
* @param start
* @param end
*/
public void addEdge(int start,int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
/**
* 打印节点
* @param v
*/
private void dispalyNode(int v) {
System.out.print(nodeList[v].label+"\t");
}
/**
* 深度优先搜索
*/
public void dfs() {
nodeList[0].wasVisited = true; //修改访问标志为访问过的
dispalyNode(0);
stack.push(0); //存放的是节点的位置
while (!stack.isEmpty()) {
int v = getAdjUnvisitedVertex(stack.peek());
if(v == -1) {
stack.pop(); //没有未被访问的相邻节点,就是找完了
}else {
nodeList[v].wasVisited = true;
dispalyNode(v);
stack.push(v);
}
}
//到这所有的节点都访问玩了,需要把访问状态改回去
for (int i = 0; i < nNode; i++) {
nodeList[i].wasVisited = false;
}
}
/**
* 获取指定顶点相邻接的未被访问节点
* @param v
* @return
*/
private int getAdjUnvisitedVertex(int v) {
for (int i = 0; i < nNode; i++) {
if(adjMat[v][i] == 1 && !nodeList[i].wasVisited) { //代表两个顶点之间是联通的,并且这个顶点没有被访问过
return i;
}
}
return -1; //没有找到
}
}
测试代码:
public static void main(String[] args) {
Graph graph = new Graph();
graph.addNode('A');
graph.addNode('B');
graph.addNode('C');
graph.addNode('D');
graph.addEdge(0,1);
graph.addEdge(0,2);
graph.addEdge(0,3);
graph.addEdge(1,3);
graph.dfs();
}
表示这个图:
运行结果:
图的广度优先搜索
import java.util.LinkedList;
import java.util.Queue;
/**
* @ClassName Graph1
* @Description 图的广度优先搜索
* @Author lzq
* @Date 2019/6/19 05:27
* @Version 1.0
**/
public class Graph1 {
private final int MAX_VERTS = 20; //表示一个图节点能连接的最大定点数
private Node[] nodeList; //顶点数组
private int[][] adjMat; //邻接矩阵,用来存方节点之间关系的
private int nNode; //当前顶点数量
private Queue<Integer> queue; //广度优先搜索用到的队列
public Graph1() {
nodeList = new Node[MAX_VERTS];
adjMat = new int[MAX_VERTS][MAX_VERTS];
nNode = 0;
for (int i = 0; i < MAX_VERTS; i++) {
for (int j = 0; j < MAX_VERTS; j++) {
adjMat[i][j] = 0;
}
}
queue = new LinkedList<>();
}
/**
* 添加节点
* @param lab
*/
public void addNode(char lab) {
nodeList[nNode++] = new Node(lab);
}
/**
* 添加节点直接的边
* @param start
* @param end
*/
public void addEdge(int start,int end) {
adjMat[start][end] = 1;
adjMat[end][start] = 1;
}
/**
* 打印节点
* @param v
*/
private void dispalyNode(int v) {
System.out.print(nodeList[v].label+"\t");
}
/**
* 广度优先搜索
*/
public void bfs() {
nodeList[0].wasVisited = true; //修改访问标志为访问过的
dispalyNode(0);
queue.add(0); //存放的是节点的位置
int v2;
while (!queue.isEmpty()) {
int v1 = queue.remove(); //从队头取出一个顶点
while ((v2 = getAdjUnvisitedVertex(v1)) != -1) {
nodeList[v2].wasVisited = true;
dispalyNode(v2);
queue.add(v2);
}
}
//到这所有的节点都访问玩了,需要把访问状态改回去
for (int i = 0; i < nNode; i++) {
nodeList[i].wasVisited = false;
}
}
/**
* 获取指定顶点相邻接的未被访问节点
* @param v
* @return
*/
private int getAdjUnvisitedVertex(int v) {
for (int i = 0; i < nNode; i++) {
if(adjMat[v][i] == 1 && !nodeList[i].wasVisited) { //代表两个顶点之间是联通的,并且这个顶点没有被访问过
return i;
}
}
return -1; //没有找到
}
}
测试:
public static void main(String[] args) {
Graph1 graph = new Graph1();
graph.addNode('A');
graph.addNode('B');
graph.addNode('C');
graph.addNode('D');
graph.addNode('E');
graph.addEdge(0,1);
graph.addEdge(0,2);
graph.addEdge(0,3);
graph.addEdge(1,3);
graph.addEdge(3,4);
graph.bfs();
}