图的遍历

来源:互联网 发布:山大网络教育模拟题 编辑:程序博客网 时间:2024/06/05 15:05

图的遍历方法主要有两种:(1)深度优先遍历,类似于树的先序遍历;(2)广度优先遍历,类似于树的层序遍历。

遍历设计三思:(1)图没有首尾之分,所以算法中必须指定访问的第一个结点;(2)图的遍历过程中可能会构成一个回路,造成死循环,所以要考虑到所有的死循环问题;(3)一个结点可能和多个结点都是邻接关系,所以要使一个结点的所有邻接结点按照某种次序被访问。

图又分连通图和非连通图,连通图中,从初始结点出发,一定存在路径和图中的所有其他结点相连。而非连通图,从某一结点开始并不能访问图中的所有结点。所以,我们要分开设计。

连通图的深度优先遍历:

从初始结点出发,遵守深度优先规则,即在图的所有邻接结点中,每次都在访问完当前结点后首先访问当前结点的第一个邻接结点,该算法是一个递归算法,设计如下。

(1)访问结点v并标记结点v为已访问;

(2)查找结点v的第一个邻接结点w;

(3)若结点w存在,则继续执行,否则算法结束;

(4)若结点w尚未被访问,则以结点w开始进行深度优先遍历(递归)访问结点w;

(5)若结点w已被访问过,则查找结点v的w邻接结点的下一个邻接结点w,转步骤3。

注:该递归算法属于回溯算法。

连通图的广度优先遍历:

类比于树的分层遍历,广度优先遍历需要一个队列以保存访问过的结点顺序,以便按访问过的结点顺序来访问这些结点的邻接结点,设计如下。

(1)访问结点v并标记结点v为已访问;

(2)结点v入队列;

(3)当队列非空,则继续执行,否则算法结束;

(4)出队列取得队头结点u;

(5)查找结点u的第一个邻接结点w;

(6)若结点u的邻接结点w不存在,转步骤3,否则循环执行以下:

1、若结点w未被访问,则访问结点w,并标记w为已访问;

2、结点w入队列;

3、查找结点u的w邻接结点的下一个邻接结点w,转步骤6;

非连通图遍历:鉴于上面的分析,我们可以把每一个结点都作为一次初始结点进行深度或广度优先遍历,并根据结点的访问标记来判断是否需要访问该结点,就一定可以访问非连通图中所有结点。

代码实现,对下图进行遍历:


首先创建访问类:

package Map;/*** @author sun* 创建时间:2017年5月8日上午9:40:06*//*搬用访问树结点概念,我们把对图结点的访问也封装成类 * 即当访问到一个结点时把要进行的操作放在该类中 * 我们只进行输出操作 * */public class Visit {public void print(Object item){System.out.print(item+" ");}}

设计遍历函数,函数作为前文邻接矩阵图类AdjMWGraph的成员函数,这里只列出相关部分函数(注:需要引入顺序队列包)

//递归设计深度和广度优先遍历private void depthFirstSearch(int v,boolean[] visited,Visit vs)throws Exception{//连通图以v为初始结点序号,访问操作为vs的深度优先遍历//数组visited标记了相应结点是否已经访问过,0表示未访问,1表示已访问vs.print(getValue(v));//访问该结点visited[v] = true;//已访问标记int w = getFirstNeighbor(v);//取第一个邻接结点while(w!=-1){//当邻接结点存在时,才进行循环if(!visited[w])//如果该结点w未被访问过depthFirstSearch(w,visited,vs);//以w为初始结点递归w = getNextNeighbor(v,w);//如果当前w被访问过,则取v的下一个邻接结点}}private void broadFirstSearch(int v,boolean[] visited,Visit vs)throws Exception{//连通图以v为初始结点序号,访问操作为vs的广度优先遍历//数组visited标记了相应结点是否已经访问过,0表示未访问,1表示已访问//借助队列实现int u,w;SeqQueue queue = new SeqQueue();//创建顺序队列vs.print(getValue(v));//访问结点vvisited[v] = true;//已访问标记queue.append(new Integer(v));//结点v入队列while(queue.notEmpty()){//判断队列非空u = ((Integer)queue.delete()).intValue();//出队列w = getFirstNeighbor(u);//取结点u的第一个邻接结点while(w!=-1){//当前邻接结点存在时循环if(!visited[w]){vs.print(getValue(w));visited[w] = true;queue.append(new Integer(w));//结点w入队列}//取结点u的邻接结点w的下一个邻接结点w = getNextNeighbor(u,w);}}}public void depthFirstSearch(Visit vs)throws Exception{//非连通图的深度优先遍历boolean[] visited = new boolean[getNumOfVertices()];for(int i=0;i<getNumOfVertices();i++)visited[i] = false;//把所有结点置为为被访问for(int i=0;i<getNumOfVertices();i++)if(!visited[i])//如果结点i未被访问,以该结点为初始结点深度优先遍历depthFirstSearch(i,visited,vs);}public void broadFirstSearch(Visit vs)throws Exception{//非连通图的广度优先遍历boolean[] visited = new boolean[getNumOfVertices()];for(int i=0;i<getNumOfVertices();i++)visited[i] = false;//把所有结点置为为被访问for(int i=0;i<getNumOfVertices();i++)if(!visited[i])//如果结点i未被访问,以该结点为初始结点广度优先遍历broadFirstSearch(i,visited,vs);}

主函数测试:

package Map;/*** @author sun* 创建时间:2017年5月9日上午9:38:12*///遍历测试public class TestMySearch {//构造图public static void createGraph(AdjMWGraph g,Object[] v,int n,RowColWeight[] rc,int e)throws Exception{for(int i=0;i<n;i++)g.insertVertex(v[i]);for(int k=0;k<e;k++)g.inserEdge(rc[k].row,rc[k].col, rc[k].weight);}public static void main(String[] args) {final int maxVertices = 100;Visit vs = new Visit();int n=5,e=5;AdjMWGraph g = new AdjMWGraph(maxVertices);Character[] a = {new Character('A'),new Character('B'),new Character('C'),new Character('D'),new Character('E')};RowColWeight[] rcw = {new RowColWeight(0,1,10),new RowColWeight(0,4,20),new RowColWeight(1,3,30),new RowColWeight(2,1,40),new RowColWeight(3,2,50)};try{createGraph(g,a,n,rcw,e);System.out.print("深度优先搜索序列为:");g.depthFirstSearch(vs);System.out.println();System.out.print("广度优先搜索序列为:");g.broadFirstSearch(vs);System.out.println();}catch(Exception ex){ex.printStackTrace();}}}/* 深度优先搜索序列为:A B D C E 广度优先搜索序列为:A B E D C  */


0 0