图遍历介绍
所谓图的遍历,即是对节点的访问,一个图有那么多节点,如何遍历这些节点,需要特定策略,一般有两种访问策略:1.深度优先遍历2.广度优先遍历
深度优先遍历基本思想
1.深度优先遍历,从初始访问节点出发,初始访问节点可能有很多邻接节点,深度优先遍历的策略就是首先访问第一个邻接节点,然后再以这个被访问的邻接节点作为初始节点,访问它的第一个邻接节点,可以这样理解,每次都在访问完当前节点后首先访问当前节点的第一个邻接节点
2.我们可以看到,这样的访问策略是优先往纵向深入挖掘,而不是对一个节点的所有邻接节点进行横向访问
3.显然,深度优先搜索是一个递归的过程
深度优先遍历算法步骤
1.访问初始节点v,并标记节点v已访问
2.查找节点v的第一个邻接节点w
3.若w存在,则继续执行4,若w不存在,则回到第一步,将从v的下一个节点继续
4.若w未被访问,对w进行深度优先递归遍历(即把w当作一个v,然后进行步骤123)
5.查找v的w邻接节点的下一个邻接节点,转到步骤3
代码实现
//得到一个邻接节点下标w
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;
}
//深度优先遍历算法
//i第一次就是0
public void dfs(boolean[] isVisited,int i) {
//首先我们访问该节点,输出
System.out.println(getValueByIndex(i)+"->");
//将节点设置为已访问
isVisited[i]=true;
//查找节点i的第一个邻接节点w
int w=getFirstNeighbor(i);
while(w!=-1) {//说明有
if(!isVisited[w]) {
dfs(isVisited,w);
}
//如果w节点已经被访问过
w=getNextNeighbor(i, w);
}
}
//对dfs进行重载,遍历我们所有的节点,并进行dfs
public void dfs() {
//对所有的节点进行dfs
for(int i=0;i<getNumOfVertex();i++) {
if(!isVisited[i]) {
dfs(isVisited,i);
}
}
}
广度优先遍历基本思想
图的广度优先搜索类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的节点顺序,以便按这个顺序来访问这些节点的邻接节点
广度优先遍历算法步骤
1.访问初始节点v并标记v已访问
2.节点v入队列
3.当队列非空时继续执行,否则算法结束
4.出队列,取得队头结点u
5.查找节点u的第一个邻接节点w
6.若节点u的邻接节点w不存在,则转到3,否则继续执行下面三个步骤
6.1若节点w尚未访问,则访问节点w并标记为已访问
6.2节点w入队列
6.3查找节点u的继w邻接节点后的下一个邻接节点w,转到6
代码实现
// 广度优先遍历
public void bfs(boolean[] isVisited, int i) {
int u;// 表示队列头节点的下标
int w;// 邻接节点w
// 队列,记录节点的访问顺序
LinkedList queue = new LinkedList();
// 访问节点,输出节点信息
System.out.println(getValueByIndex(i));
// 标记为已访问
isVisited[i] = true;
// 将节点加入队列
queue.addLast(i);
while (!queue.isEmpty()) {
// 取出队列的头节点下标
u = (Integer) queue.removeFirst();
// 得到第一个邻接节点的下标w
w = getFirstNeighbor(u);
while (w != -1) {
// 是否访问过
if (!isVisited[w]) {
System.out.println(getValueByIndex(w));
// 标记为已访问
isVisited[w] = true;
// 入队
queue.addLast(w);
}
// 以u为前驱点,找w后面的下一个邻接点
w = getNextNeighbor(u, w);
}
}
}
// 重载bfs,考虑有不连通节点的情况
public void bfs() {
isVisited = new boolean[vertexList.size()];
for (int i = 0; i < getNumOfVertex(); i++) {
if (!isVisited[i]) {
bfs(isVisited, i);
}
}
}