图的深度优先搜索遍历算法分析及其应用
42 #define- E 0 青海师范大学学报(自然科学版) edgenede*firstedge; 2007年 Booleam visited[MAX—VERTEX—NUMJ; typedef struct edgenede }vex.nde,eAdjHst[MAX—VERTEXNUM]; —typedef struct {hat adjvex;edgenede*nextedge;}edgenede; typedef struct vexnede {vexnode vertices; int vexnum,edgenum; {char data; 2.2构造算法 }AI ̄mph; 根据上述结构,我们可以构造出建立图G的邻接表的具体算法. void creatgraph(ALGraph&G) { i,j,k;edgenede*s; //图的邻接表 prinff(”以编号为顺序输入顶点信息(每个顶点占两位):”); f0lr(i=O;i<n;i++) {scaIlf(”%2d,,,&adjlist[i].atda); Adjlist[i].ifrstedge= E;} prm ̄(,输入组成边的点对(如:边为(1,2),则输入1 2/\Il,,); for(k=l;k<=e;k++) {prinff( ,第%d条边的点对:”,k);scarf(”%d%d,,,蕊, ); S=(edgenede*)mailoc(sizeof(edgenede));S一>adjvex=j; s一>nextedge=Adjlist[i].ifrstedge;Adjlist[i].ifrstedge=s; s=(edgenede*)malloc(sizeof(edgenede));S一>adjvex=i; s一>nextedge=Adjlist[j].ifrstedge;Adjlist[j].ifrstedge=s;}} 根据图的结构建立其所对应的邻接表后,可以用下述算法打印出邻接表. void show(ALGmph&G) {int i;edgenede*s; or(i=O;i<n;i++)f {s=AdjList[i].fisrtedge; {prinff(”%9d:一”,AdjList[i].data); if(Adjlist[i].ifrstedge!:FALSE) while(s!=FALSE) {prntif(”%5 ”,S一>adjvex); s=s一>nextedge;}} prnitf( \Il,,);}} 一显然,在建立邻接表的过程中,对邻接点的访问是无次序的,所以同 Vl 个图的邻接表表示不唯一.如图2所示是图G以顶点编号为0,1,2,1 V2 V3 2 V4 3 4 V5 3,4,5,6,7的输入顺序建立的邻接表. 3图的DFS遍历 5 V6 V7 图的遍历是从图中某个顶点出发,沿着某条搜索路径对图中其它顶6 V8 点访问且仅被访问一次.通常有两条遍历图的路径:深度优先搜索7 (Depth First Search)和广度优先搜索(Breadth Fisrt Search).它们对无向图 和有向图均适用. 3.1 DFS遍历的基本思想 图2图G的邻接表 假设初始状态是图中所有顶点未曾被访问,从图中某个顶点Vi出发,访问此顶点,然后依次从Vi 的未被访问的邻接点出发深度优先遍历图,直至图中所有和Vi有路径的顶点都被访问到为止;若此时 维普资讯 http://www.cqvip.com 第3期 刘萍,冯桂莲:图的深度优先搜索遍历算法分析及其应用 43 图中尚有顶点未被访问,则另选图中未曾访问的顶点为起始点,重复上述过程,直至图中所有顶点都被 访问为止 2. 3.2 DFS遍历的具体步骤 (1)先将图中所有顶点标记为“未被访问”标志; (2)输出起始顶点,同时置起始顶点“已访问”标记; (3)将起始顶点进栈; (4)当栈不为空时重复执行以下步骤: ①取当前栈顶顶点; ②若栈顶顶点存在未被访问的邻接顶点,则选择一个顶点并输出; ③置该顶点为“已访问”标志,将该顶点进栈;否则,当前顶点退栈. 3.3 DFS遍历的算法设计 结合示例,我们可以设一个辅助数组visited[n],将其初始值均置为“0”,一旦访问了顶点vi,便将 ivsitd[ie]置为“1”,其具体算法如下: voiddfstraverse(ALGmph&G) ,edgenede*・p; {int i;for(i=O;i<n;i++)visited[i]=FALSE; for(i=0;i<n;i++)printf(”%d一>”,AdjListEi].data); ivsitedEi]=TRUE; P=AdjList[i].firstedge; if(!visited[i]) while(p!:FALSE) dfs(G,i);} void dfs(ALGraph&G,int i){static int ivsitdlMAX—VERTEX—NUM];e{if(!visitd[ep一>adjvex]) dfs(G,P一>adjvex); P=P一>nextedge;}} 从上面算法看出,进行图的遍历时,对图中的每个顶点至多调用一次 ,因此,图的遍历过程实际 上是对每个顶点查找其邻接点的过程.此外,由于图的邻接表是不唯一的,所以由不同的邻接表得到的 图的遍历结果也是不相同的. 4主程序 在给出了数据结构类型和具体操作的算法之 后,可以编辑出以下主程序: void main() {int x;ALGraph G;creatgraph(G); p血tf( 输出如下邻接表:\n”);show(G); printf( \n输入访问出发点的顶点编号:”); s ̄anf(”%d,,, ); printf(”该图的深度优先搜索遍历序列为:\n\ t,,).dfs(G,x); prinff(”\b\b,,);} 5运行结果 该程序已经在Visual C++环境中调试通过,运 行时输入的具体数据和相应结果如图3所示: 图3程序运行结果 维普资讯 http://www.cqvip.com 青海师范大学学报(自然科学版) 2O07年 6 dfs遍历序列结果讨论 (1)只给定一个无向图,则dfs遍历序列不一定唯一.从图的某顶点vi出发进行搜索时,若vi的邻 接点有多个尚未访问,可任选一个访问. (2)只有确定了图的邻接表的内容及起始顶点, 遍历序列才能唯一.因为邻接表里的邻接点域的 内容与建表时的输人次序相关. 7基于dfs算法的应用 (1)求无向图中连通分量的个数 求解该问题只要在算法dfstraverse中加人一个计数器count,每调用一次 后,使count加1,最后 count的值就是无向图中连通分量的个数. (2)求解无向图中通过给定顶点Vi的简单回路的算法[3】 从给定的顶点Vi出发进行深度优先搜索,搜索过程中每访问一个顶点,判别它是否为vi,若是,则 说明已找到一条回路;杏则继续搜索.因此,用一个顺序栈记录构成回路的顶点序列,把访问顶点的操作 改为顶点的人栈,此时若从某一顶点出发搜索完再回溯,则做退栈操作.另外再设置一个标志found,其 初值为FALSE,当找到回路后改为TRUE. 综上所述,图的结构比较复杂,在编写图的DFS算法和程序时,关键要掌握它的遍历思想,并且能 使用一些编程技巧和经验对程序进行优化.在完全理解DFS算法的基础上,再去解决有关图的一些问 题就显得容易了. 参考文献: [1】严蔚敏,吴伟民.数据结构[M】.北京:清华大学出版社.1997:160-178. [2】胡学钢.数据结构算法设计指导[M】.北京:清华大学出版社.1999:198-216. [3】于晓敏,唐丽.用遍历方式求解图中是否存在回路问题[J].齐齐哈尔大学学报,2OO4,2: ̄46. Analysis and Application For Depth—first Search Algorithm Of Graph LIU胁 ,FENG Gui-lian (1.Department OfComputer,Qinghai Nationalities University,Xining 810007,China; 2.Department of Electronic Engineering and Information Science。Qinghai Nationaliites University,yani ̄810007,China) Abstract:This paper analyzes carefully the Depth—first Search Algorithm ofthe Graph that regarded the adja— eeney list as storage struc ̄re through particular examples,and also analyzes the whole program realized in ve++. At last.it produces 8咖e application based Oil this asorithm. Key words:graph;depth——first search;traversing;algorithm
因篇幅问题不能全部显示,请点此查看更多更全内容