一:广度优先遍历介绍.
广度优先遍历(BFS),广度优先遍历是尽可能的更多的把相邻的元素都遍历了,然后在访问外层的,有点像中心开花由内到外.
从图中任选一个顶点v,作为起始顶点.例如下图:BFS的遍历顺序是首先是V,然后是W1,W2,Y11,Y12,Y21,Y22.总是第一层访问完了,才访问第二层的,这就是二叉树的层序访问嘛.
二:广度优先遍历的实现.使用队列实现.
BFS的遍历序列如下:没有确定起始点就不唯一.这里是A是起点.
import java.util.LinkedList;
import java.util.Queue;
/**
* title: com.lx.algorithm.graph
* @author: lixing
* date: 2018/10/31 17:57
* description:广度优先遍历使用队列实现,(无向非连通图)非递归实现.
*/
public class BFSTest {
/**
* 存储节点信息
*/
private char[] vertices;
/**
* 存储边信息(邻接矩阵)
*/
private int[][] arcs;
/**
* 图的节点数
*/
private int vexnum;
/**
* 记录节点是否已被遍历
*/
private boolean[] visited;
/**
* 初始化
*/
public BFSTest(int n) {
vexnum = n;
vertices = new char[n];
arcs = new int[n][n];
visited = new boolean[n];
for (int i = 0; i < vexnum; i++) {
for (int j = 0; j < vexnum; j++) {
arcs[i][j] = 0;
}
}
}
/**
* 添加边
*/
public void addEdge(int i, int j) {
if (i == j) {
return;
}
arcs[i][j] = 1;
arcs[j][i] = 1;
}
/**
* 设置节点集
*/
public void setVertices(char[] vertices) {
this.vertices = vertices;
}
/**
* 设置节点访问标记
*/
public void setVisited(boolean[] visited) {
this.visited = visited;
}
/**
* 打印遍历节点
*/
public void visit(int i) {
System.out.print(vertices[i] + " ");
}
/**
* 输出邻接矩阵
*/
public void pritf(int[][] arcs){
for(int i=0;i<arcs.length;i++){
for(int j=0;j<arcs[0].length;j++){
System.out.print(arcs[i][j]+ "\t");
}
System.out.println();
}
}
/**
* 实现广度优先遍历
*/
public void bfs() {
// 初始化所有的节点的访问标志
for (int v = 0; v < visited.length; v++) {
visited[v] = false;
}
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = 0; i < vexnum; i++) {
if (visited[i] == false) {
visited[i] = true;
// 打印当前已经遍历的节点
visit(i);
// 添加到队列里面
queue.add(i);
// 只要队列不为空
while (!queue.isEmpty()) {
// 出队节点,也就是这一层的节点.
int k = queue.poll();
// 遍历所有未被访问的邻接节点,放入队列
for (int j = 0; j < vexnum; j++) {
// 也就是访问这一层剩下的未被访问的节点
if (arcs[k][j] == 1 && visited[j] == false) {
visited[j] = true;
visit(j);
queue.add(j);
}
}
}
}
}
System.out.println();
pritf(arcs);
}
public static void main(String[] args) {
BFSTest g = new BFSTest(9);
char[] vertices = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'};
// 设置顶点集
g.setVertices(vertices);
// 添加边
g.addEdge(0, 1);
g.addEdge(0, 5);
g.addEdge(1, 0);
g.addEdge(1, 2);
g.addEdge(1, 6);
g.addEdge(1, 8);
g.addEdge(2, 1);
g.addEdge(2, 3);
g.addEdge(2, 8);
g.addEdge(3, 2);
g.addEdge(3, 4);
g.addEdge(3, 6);
g.addEdge(3, 7);
g.addEdge(3, 8);
g.addEdge(4, 3);
g.addEdge(4, 5);
g.addEdge(4, 7);
g.addEdge(5, 0);
g.addEdge(5, 4);
g.addEdge(5, 6);
g.addEdge(6, 1);
g.addEdge(6, 3);
g.addEdge(6, 5);
g.addEdge(6, 7);
g.addEdge(7, 3);
g.addEdge(7, 4);
g.addEdge(7, 6);
g.addEdge(8, 1);
g.addEdge(8, 2);
g.addEdge(8, 3);
System.out.print("广度优先遍历(队列):");
g.bfs();
}
}
运行结果:
三:深度优先对比广度优先遍历.
1. 两种算法的时间复杂度都是一样的.
2. 深度优先遍历涉及的辅助数据结构是栈,广度优先遍历涉及的队列.
3. 广度优先遍历占用的内存比较多是横向元素入队的,如果这一层元素比较多,那么队内的元素就比较多,而深度优先遍历的栈内元素是深入栈的,每一条路径不会存储太对的元素,栈内元素依次出栈,占用内存减少.