基于栈的非递归深度优先遍历算法设计与实现[权威资料]
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于栈的非递归深度优先遍历算法设计与实现[权威资料] 基于栈的非递归深度优先遍历算法设计与实现
本文档格式为WORD,感谢你的阅读。
摘要:深度优先遍历是图的一种重要遍历方法,该文主要介绍在邻接矩阵存储
方式下,利用栈实现对稠密图进行深度优先非递归遍历的算法设计及实现过程。
关键词:深度优先;算法;非递归;栈
TP311 A 1009-3044(2014)03-0470-03
图是一种重要的数据结构,在实际生活中应用非常广泛,如计算机网络、电力
网络、交通信号网路等。图可分为有向图,无向图,连通图,非联通图,稠密图,稀疏图等,该文仅以图1为例介绍无向连通稠密图的存储以及基于栈的非递归深度优先遍历算法。
1 图的存储表示
图在计算机中的物理存储方式主要有邻接矩阵和邻接表两种,其中邻接矩阵适
用于稠密图,邻接表适用于稀疏图。该文例图可视为稠密图,因此图的物理存储采用邻接矩阵(二维数组adj[][])实现,下面是创建邻接矩阵adj[][]的C语言代码: void create_matrix(int adj[V+1][V+1])
int E,u,v,wgt;//表示边的条数
printf("请输入边数:");
scanf("%d",
E);
for(int i=1;i<=E;i++)
printf("请输入第%d条边",i);
scanf("%d %d %d",
wgt);
adj[u][v]=adj[v][u]=wgt;
图1利用create_matrix函数建立的邻接矩阵存储示意图如图2所示,我们可以发现图的邻接矩阵是对称矩阵。
2 图的深度优先遍历思想
深度优先搜索是图的重要遍历方法之一,遍历过程的实质是对每个顶点查找其邻接点的过程,类似于树的先根遍历,具体思路为:
1)从图中任一顶点v开始,当顶点v未被访问过时,做访问标记;
2)遍历v的所有邻接点:
如果邻接点u未被访问过:
?输出顶点u;
?做访问标记;
?遍历u的所有邻接点;
为了保证图中的各顶点在遍历过程中访问且仅访问一次,需要为每个顶点设一个访问标记,该文利用数组visited[V]实现,数组初始值设置为0,表示所有顶点均未被访问。
3 深度优先遍历的递归算法
深度优先遍历的递归算法如下:
void DF(int v) //深度优先遍历的递归算法
int u;
visited[v] = ++id; //设置顶点v的访问标记
printf("%d—",v);
for (int t = 1; t <= V; t++) //依次判断图中每个顶点进行如下判断
//如果顶点v、t之间存在边且t未被访问过,则对顶点t进行深度优先遍历;
if (adj[v][t] ~= 0
visited[t] == 0)
DF(t);
深度优先遍历的递归算法过程清晰、实现简单,在国内大部分数据结构的教材中均采用此种方式介绍深度优先遍历,在教学过程中由于受课时等因素的限制,教师往往也只讲授遍历的递归算法。但由于递归算法的时间效率低下,空间占用量高,在实际应用程序中人们往往采用非递归方式进行深度优先遍历。
4 深度优先的非递归算法
深度优先的非递归算法需要借助栈实现,算法的基本思路如下:
1)初始化栈;
2)对所有节点做未访问标记;
3)起始节点入栈;
4)while栈不为空时:
?栈顶顶点v出栈;
?如果顶点v未标记为已访问,则
打印v;
标记v为已访问;
遍历顶点v的邻接点,如果邻接点u未被标记为已访问,则u入栈;
对于一个含有V个顶点的无向连通图,深度优先遍历的非递归算法在最好的情况下(每个顶点仅有两条边相连)每个顶点仅被访问一次,时间复杂度为O(n);而在最坏的情况下(图为完全图时),搜索第i层结点时将会有n-i个结点入栈,最多在栈中存储(n-2)*(n-1)/2个结点,此时的时间复杂度与递归算法类似,为O(n2)。
深度优先遍历的非递归算法具体程序代码如下:
void dfVisit(int v)
SqStack s; //声明一个顺序栈s
init(s); //初始化栈
for(int i=1;i<=V;i++)//依次对图中每个顶点设置访问标记
visited[i] = 0; //0表示未访问
Push(s,v); //顶点v入栈
printf("DF vertext by iteration:");
while (~isEmpty(s)) //设置循环终止条件为栈空
v =Pop(s); //用顶点v接收出栈元素
if (~visited[v])//如果顶点v未被访问
printf("%c—",v+64);//打印顶点v
visited[v]=++id;//为顶点v设置访问标记
for(int u=1;u<=V;u++)//循环用于访问v的每个邻接点u
if (visited[u]==0
adj[v][u]~=0)//如果顶点v的邻接点u未被访问
Push(s,u);//将邻接点u入栈
}//end-for
}//end-if
}//end-while
利用深度优先遍历的非递归算法dfVisit()对图1进行遍历时,顶点的遍历顺序及入栈和出栈过程如图3和图4所示。图4中,新入栈的邻接点用斜体和灰色背景表示,如当遍历顶点A的邻接点时,B、C、D、G顶点先后入栈。
5 结束语
根据图的深度优先遍历定义,我们知道图的深度优先遍历结果不唯一。我们可以设计不同的存储结构来存储和表示图,并在此基础上编写不同的算法进行遍历,