- 图的遍历
- 深度优先遍历
- 广度优先遍历
深度优先遍历
- 介绍
- 从初始访问顶点出发,初始访问顶点可能会有很多个邻接顶点,深度优先遍历的方法是先访问第一个未被访问过的邻接顶点,然后以这个邻接顶点作为初始顶点,再访问它的第一个未被访问过的邻接顶点,以此类推。
- 如果访问到某一个顶点,发现它的邻接顶点都被访问过,就访问它上一个顶点的其他未被访问过的邻接顶点。如果这样回退到最初始的顶点,发现所有的邻接顶点都被访问过,则遍历结束。
- 这是一个递归过程
- 算法
- 1.访问初始顶点 v ,并且将其标记为已访问
- 2.访问顶点 v 的第一个邻接顶点 neighbor
- 3.如果 neighbor 存在,则执行步骤 4 ,否则,回到步骤 1,从 v 的下一个顶点继续
- 4.如果 neighbor 未被访问,则对其进行深度优先遍历
- 5.访问结束之后,访问 v 的下一个邻接顶点
- 6.所有顶点访问过之后结束
广度优先遍历
- 介绍
- 从初始访问顶点出发,初始访问顶点可能会有很多个邻接顶点,广度优先遍历的方法是依次访问所有的未被访问过的邻接顶点,然后以第一个未被访问过的邻接顶点作为初始顶点,再访问它的所有的未被访问过的邻接顶点,以此类推。
- 如果访问到某一个顶点,发现它的邻接顶点都被访问过,就访问它上一个顶点的其他邻接顶点的未被访问过的邻接顶点。如果这样回退到最初始的顶点,发现所有的邻接顶点都被访问过,则遍历结束。
- 遍历过程中需要有一个队列来记录访问顺序,以便以这个顺序来访问他们的邻接顶点
- 算法
- 1.访问初始顶点 v ,并且将其标记为已访问
- 2.将这个顶点加入到队列中
- 3.如果队列非空,执行步骤4,否则结束
- 4.取出队列的头元素
- 5.访问该头元素的所有未被访问过的邻接顶点,标为已访问,并加入到队列中
- 6.如果该有元素没有未被访问过的邻接顶点,转到步骤3
代码
- 除了深度和广度优先遍历算法,还定义了插入顶点、插入边、显示邻接矩阵的方法,还有顶点字母与邻接矩阵下标数字一一对应的方法,或者某个顶点的第一个邻接顶点以及下一个邻接顶点的方法
- 代码如下
public class Graph {
private ArrayList<String> vertexList;//顶点集合
private int[][] edges;//邻接矩阵
private boolean[] isVisited;//表示顶点是否被访问
//n是顶点个数
public Graph(int n) {
this.vertexList = new ArrayList<>(n);
this.edges = new int[n][n];
this.isVisited = new boolean[n];
}
//插入节点
public void insertVertex(String s){
vertexList.add(s);
}
//插入边
public void insertEdges(int v1, int v2){
edges[v1][v2] = 1;
edges[v2][v1] = 1;
}
//返回数字对应的顶点
public String getVertex(int i){
return vertexList.get(i);
}
//显示邻接矩阵
public void showGraph(){
for (int i = 0; i < vertexList.size(); i++) {
for (int j = 0; j < vertexList.size(); j++) {
System.out.print(edges[i][j]+" ");
}
System.out.println();
}
}
//得到顶点的第一个邻接顶点对应的数字
public int getFirstNeighbor(int index){
for (int i = 0; i < vertexList.size(); i++) {
if (edges[index][i] == 1){
return i;
}
}
return -1;
}
//获取下一个顶点
public int getNextNeighbor(int v1, int v2){
for (int i = v2+1; i < vertexList.size(); i++) {
if (edges[v1][i] == 1){
return i;
}
}
return -1;
}
/**
* 深度优先遍历算法
* @param isVisited 顶点访问情况
* @param i 对应的顶点
*/
public void deepFirstSearch(boolean[] isVisited, int i){
//首先输出第一个顶点,并标记为已访问
System.out.print(getVertex(i)+"-->");
isVisited[i] = true;
//找到下一个顶点
int neighbor = getFirstNeighbor(i);
while (neighbor != -1){
if (!isVisited[neighbor]){
deepFirstSearch(isVisited, neighbor);
}
neighbor = getNextNeighbor(i,neighbor);
}
}
//遍历所有顶点
public void deepFirstSearch(){
for (int i = 0; i < vertexList.size(); i++) {
if (!this.isVisited[i]){
deepFirstSearch(this.isVisited,i);
}
}
}
/**
* 广度优先搜索
* @param isVisited
* @param i
*/
public void breadthFirstSearch(boolean[] isVisited, int i){
int m;
int nextNeighbor;
LinkedList<Integer> queue = new LinkedList<>();
//首先输出第一个顶点,并标记为已访问
System.out.print(getVertex(i)+"-->");
isVisited[i] = true;
queue.addLast(i);
while (!queue.isEmpty()){
m = queue.removeFirst();
nextNeighbor = getFirstNeighbor(m);
while (nextNeighbor != -1){
if (!isVisited[nextNeighbor]){
System.out.println(getVertex(nextNeighbor)+"-->");
isVisited[nextNeighbor] = true;
queue.addLast(nextNeighbor);
}
nextNeighbor = getNextNeighbor(m, nextNeighbor);
}
}
}
//广度所有顶点
public void breadthFirstSearch(){
for (int i = 0; i < vertexList.size(); i++) {
if (!this.isVisited[i]){
breadthFirstSearch(this.isVisited,i);
}
}
}
}
测试代码
public class GraphDemo {
public static void main(String[] args) {
String[] vertexs = {"0","1","2","3","4","5","6","7"};
int n = vertexs.length;
Graph graph = new Graph(n);
for (int i = 0; i < n; i++) {
graph.insertVertex(vertexs[i]);
}
graph.insertEdges(0,1);
graph.insertEdges(0,2);
graph.insertEdges(1,3);
graph.insertEdges(1,4);
graph.insertEdges(2,5);
graph.insertEdges(2,6);
graph.insertEdges(5,6);
graph.insertEdges(3,7);
graph.insertEdges(4,7);
graph.showGraph();
System.out.println("deepth first search");
//graph.deepFirstSearch();
System.out.println();
System.out.println("breadth first search");
graph.breadthFirstSearch();
}
}