图的DFS递归和非递归
2013-08-27 03:44 youxin 阅读(3753) 评论(1) 编辑 收藏 举报看以前写的文章:
图的BFS:http://www.cnblogs.com/youxin/p/3284016.html
DFS:http://www.cnblogs.com/youxin/archive/2012/07/28/2613362.html
递归:
参考了算法导论
int parent[50];
int color[50];//0代表white,1 gray 2 black static int time=0; int d[50];//顶点v第一次被发现(并置v为gray色) int f[50];//结束检测v的邻接表(并置v为黑色) void DFS(Graph G,int u); void DFSTraverse(Graph G,void (*Visit)(VextexType v)) { visitFunc=Visit; for(int i=0;i<G.vexnum;i++) { color[i]=0; parent[i]=-1; } time=0; for(int i=0;i<G.vexnum;i++) { if(color[i]==0) //未访问 DFS(G,i); } } void DFS(Graph G,int u) { color[u]=1;//white vextex has just been discovered visitFunc(G.vertices[u].data); time=time+1; d[u]=time; ArcNode *p=G.vertices[u].firstarc; while(p) { int v=p->adjvex; if(color[v]==0) { parent[v]=u; DFS(G,v); } p=p->nextarc; } color[u]=2;//black,it's finished f[u]=time=time+1; }
DFSTraverse(G,visit); cout<<endl; for(int i=0;i<G.vexnum;i++) cout<<i<<ends<<parent[i]<<endl; cout<<endl; for(int i=0;i<G.vexnum;i++) cout<<i<<ends<<d[i]<<"----"<<f[i]<<endl;
可以看到DFS输出:
v1 v3 v7 v6 v2 v5 v8 v4。
非递归要用到栈。
void DFS2(Graph G,int u) { stack<int> s; visited[u]=true; s.push(u); while(!s.empty()) { int v=s.top();s.pop(); visitFunc(G.vertices[v].data); ArcNode *p=G.vertices[v].firstarc; while(p) { if(!visited[p->adjvex]) { s.push(p->adjvex); visited[p->adjvex]=true; } p=p->nextarc; } } }
写非递归时千万要记住的是,进栈时一定要设置visited[i]=true(包括原顶点);不然有些节点会重复进栈。DFS和
二叉树的先序遍历是一样的,只不过二叉树只有2个分支,要要进右分支,在进左分支,而图只要是邻接点都进去,不分先后。
下面的代码写的比较烂:(不要用,用上面的)
void DFS2(Graph G,int u) { color[u]=1;//white vextex has just been discovered visitFunc(G.vertices[u].data); time=time+1; d[u]=time; stack<int> s; ArcNode *p=G.vertices[u].firstarc; while(p) { color[p->adjvex]=1; s.push(p->adjvex); p=p->nextarc; } while(!s.empty()) { int v=s.top();s.pop(); //color[v]=1;//white vextex has just been discovered,这句话可以不要,因为在进栈时已经设置了 visitFunc(G.vertices[v].data); ArcNode *p2=G.vertices[v].firstarc; while(p2) { if(color[p2->adjvex]==0) { s.push(p2->adjvex); color[p2->adjvex]=1;//每次进栈都要设置1 } p2=p2->nextarc; } } }
这里的d[ ]和f【】不好写。
输出:
v1 v2 v4v8 v5 v3 v6 v7
邻接矩阵的非递归代码:

#include #include #define max_node 20 #define max 20000 using namespace std; int map[max_node][max_node]; void dfs(int start,int n) { stack s; int i,vis[max_node],ctop; memset(vis,0,sizeof(vis)); vis[start] = 1; printf("%d ",start); for (i = 1;i <= n;i++) if(!vis[i] && map[i][start] == 1) { vis[i] = 1; s.push(i); } while(!s.empty()) { ctop = s.top(); vis[ctop] = 1; printf("%d ",s.top()); s.pop(); for (i = 1;i <= n;i++) if(!vis[i] && map[i][ctop] == 1) { vis[i] = 1; s.push(i); } } } int main() { int s,t,n; scanf("%d",&n); memset(map,max,sizeof(map)); while(1) { scanf("%d %d",&s,&t); if(s == 0) break; map[s][t] = map[t][s] = 1; } dfs(1,n); return 0; } 输入: 8 1 2 1 3 2 4 2 5 4 8 5 8 3 6 3 7 0 0 输出: 1 3 7 6 2 5 8 4
图的深度优先算法的递归版本相当简洁好懂。将递归版本的算法改写成非递归版本的难度并不大,关键是要处理好如何正确的在搜索的过程中存储搜索树中的子结点,并正确的进行访问.一种实现采用了两个栈,而另一种则使用一个结点类型为队列的栈..
对于下面这段html代码,要求打印出每个节点的标签名和类名:
<div id='root'>
<span>123
<a href="#">
sdsd
</a>
<div>sdsd<a>这是一个a标签</a></div>
</span>
<span>456
<p>这是一个p标签</p>
</span>
</div>
面给出该算法的js实现:
(1)这是深度优先算法的递归实现
function deepTraversal(node,nodeList) {
if (node) {
nodeList.push(node);
var children = node.children;
for (var i = 0; i < children.length; i++)
//每次递归的时候将 需要遍历的节点 和 节点所存储的数组传下去
deepTraversal(children[i],nodeList);
}
return nodeList;
}
var root = document.getElementById('root')
console.log(deepTraversal(root,nodeList=[]))
(2)这是深度优先算法的递归实现
function deepTraversal(node) {
var nodeList = [];
if (node) {
var stack = [];
stack.push(node);
while (stack.length != 0) {
var childrenItem = stack.pop();
nodeList.push(childrenItem);
var childrenList = childrenItem.children;
for (var i = childrenList.length - 1; i >= 0; i--)
stack.push(childrenList[i]);
}
}
return nodeList;
}
var root = document.getElementById('root')
console.log(deepTraversal(root))
广度优先遍历
当使用广度优先遍历的时候,先依次遍历兄弟节点,然后便利兄弟节点下的子节点
结果一般为:

广度优先遍历二叉树,也就是按层次的去遍历。依次遍历根节点,然后是左孩子和右孩子。所以要遍历完当前节点的所有孩子,。根据左右孩子的顺序来输出,所以就是先进先出的原则,那么我们当然就想到了队列这个数据结构:
(1) 广度优先算法的的非递归实现
function wideTraversal(node) {
var nodes = [];
if (node != null) {
var queue = [];
queue.unshift(node);
while (queue.length != 0) {
var item = queue.shift();
nodes.push(item);
var children = item.children;
for (var i = 0; i < children.length; i++)
queue.push(children[i]);
}
}
return nodes;
}
var root = document.getElementById('root');
console.log(wideTraversal(root));
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2012-08-27 javascript 事件处理
2012-08-27 Javascript DOM 编程艺术:ENHANCING CONTENT