算法导论-第22章-基本的图算法-22.3 深度优先搜索(DFS)
2014-11-26 10:45
399 查看
一、综述
深搜策略:在深搜过程中,对于最新发现的顶点,如果它还有以此为起点的而未探测到的边,就沿此边继续探测下去。当顶点v的所有边都已被探测过后,搜索将回溯到发现顶点v有起始点的那些边。时间戳:当顶点v第一次被发现时记录下第一个时间戳d[v],当结束检查v的邻接表时,记录下第二个时间戳f[v]。v在d[v]时刻前是白色的,在时刻d[v]和f[v]之间是灰色的,在时刻f[v]之后是黑色的。
括号定理,后裔区间的嵌套,白色路径定理
边的分类:(1)树边(2)反向边(3)正向边(4)交叉边
对无向图G进行深度搜索时,G的每一条边,要么是树边,要么是反向边。
二、代码
1.Link_Graph.h
#include <iostream> #include <queue> using namespace std; #define N 100 #define WHITE 0 #define GRAY 1 #define BLACK 2 #define NONE 0 #define TREE 1 #define BACK 2 #define FORWARD 3 #define CROSS 4 struct Edge { int start; int end; int value;//边的权值 int type;//边的类型,初始值为NONE Edge *next; Edge(int s, int e, int v) :start(s),end(e),value(v),type(NONE),next(NULL){} }; struct Vertex { int d, f;//第一次被发现的时间和结束检查的时间 int color;//顶点的颜色 int p;//指向遍历结果的父结点 Edge *head;//指向以该顶点为起点的下一条边 Vertex():color(WHITE),p(0),head(NULL){}; }; class Link_Graph { public: int time; int n; Vertex *V; Link_Graph(int num):n(num) { V = new Vertex[n+1]; } ~Link_Graph(){delete []V;} void AddSingleEdge(int start, int end, int value = 1) { Edge *NewEdge = new Edge(start, end, value); //如果start点的链表为空,或者,链表第一个边的end比要加入的边的end大, 则把这条边作为第一条边(保证按end由小到大排序) if(V[start].head == NULL || V[start].head->end > end) { NewEdge->next = V[start].head; V[start].head = NewEdge; } else { Edge *e = V[start].head, *pre = e; //查找要插入的位置,循环结束条件有三种情况,1、e->end = NewEdge->end 2、e->end < NewEdge->end 3、 e == NULL while(e != NULL && e->end < end) { pre = e; e = e->next; } if(e && e->end == end) { delete NewEdge; return; } NewEdge->next = e; pre->next = NewEdge; } } void AddDoubleEdge(int a, int b, int value = 1) { AddSingleEdge(a, b, value); AddSingleEdge(b, a, value); } void DeleteSingleEdge(int start, int end) { Edge *e = V[start].head, *pre = e; while(e && e->end < end) { pre = e; e = e->next; } if(e == NULL || e->end > end) return; if(e == V[start].head) V[start].head = e->next; else pre->next = e->next; delete e; } void DeleteDoubleEdge(int a, int b) { DeleteSingleEdge(a, b); DeleteSingleEdge(b, a); } //22.3 void DFS(); void DFS_Visit(int u); void Print_Vertex_Time(); void Print_Edge_Type(); }; void Link_Graph::DFS() { int u; //对每个顶点初始化 for(u = 1; u <= n; u++) { V[u].color = WHITE; V[u].p = NULL; } //时间戳初始化 time = 0; //依次检索V中的顶点,发现白色顶点时,调用DFS_Visit访问该顶点 for(u = 1; u <= n; u++) if(V[u].color == WHITE) DFS_Visit(u); } void Link_Graph::DFS_Visit(int u) { int v; Edge *e; //将u置为灰色 V[u].color = GRAY; //使全局变量time增值 time++; //将time的新值记录为发现时间 V[u].d = time; e = V[u].head; while(e) { v = e->end; //如果顶点为白色 if(V[v].color == WHITE) { //递归访问顶点 V[v].p = u; DFS_Visit(v); //树边 e->type = TREE; } else if(V[v].color == GRAY) { //反向边/后向边,v的颜色为灰色,说明v已经遍历过,因此v是e的祖先,所以是后向边 e->type = BACK; } else if(V[v].color == BLACK) { //正向边/前向边 if(V[u].d < V[v].d) e->type = FORWARD; //交叉边 else e->type = CROSS; } e = e->next; } //以u为起点的所有边都被探寻后,置u为黑色 V[u].color = BLACK; //并将完成时间记录在f[u]中 time++; V[u].f = time; } void Link_Graph::Print_Vertex_Time() { int i; for(i = 1; i <= n; i++) { //因为书中的例子中用从u开始的字母编号的,所以输出的时候有这样一个转换 cout<<char('t'+i)<<':'; cout<<V[i].d<<' '<<V[i].f<<endl; } } void Link_Graph::Print_Edge_Type() { int i; for(i = 1; i <= n; i++) { Edge *e = V[i].head; while(e) { cout<<char(e->start+'t')<<"->"<<char(e->end+'t')<<": "; switch (e->type) { case TREE: cout<<"树边"<<endl; break; case BACK: cout<<"反向边"<<endl; break; case FORWARD: cout<<"正向边"<<endl; break; case CROSS: cout<<"交叉边"<<endl; break; } e = e->next; } } }
2.main.cpp
#include <iostream> using namespace std; #include "Link_Graph.h" int main() { //6个点,8条边 int graph[9][2]={{0,0},{1,2},{1,4},{2,5},{3,5},{3,6},{4,2},{5,4},{6,6}}; //构造一个空的图,含6个点 Link_Graph *G = new Link_Graph(6); //输入边 for(int i = 1; i <= 8; i++) { //cin>>start>>end; G->AddSingleEdge(graph[i][0], graph[i][1]); } //深度优先搜索 G->DFS(); //输出每个顶点的第一次访问时间和访问结束的时间 G->Print_Vertex_Time(); //输出每条边的类型 G->Print_Edge_Type(); delete G; return 0; }
相关文章推荐
- 算法导论-第22章-基本的图算法-22.3 深度优先搜索-22.3-7-使用栈来代替递归实现DFS
- 《算法导论》学习总结 — XX.第22章 图的基本算法
- 图的基本算法--深度优先搜索(dfs) 和 广度优先搜索(bfs)
- 算法导论习题解-第22章基本的图算法
- 算法导论 第22章 图的基本算法(四) 强连通分支
- 算法导论 第22章 图的基本算法 22.5 强联通分支
- 算法导论-第22章-基本的图算法-22.2 广度优先搜索(BFS)
- 算法导论 第22章 图的基本算法(二) 深度优先搜索
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 算法导论 第22章 图算法 22.3 深度优先搜索
- 算法导论-第22章-基本的图算法-22.2 广度优先搜索-22.2-4 用邻接矩阵方法实现BFS
- 算法导论第6部分图算法,第22章图的基本算法
- 算法导论 第22章 图的基本算法(一)
- 算法导论 第22章 图的基本算法 22.4 拓扑排序
- 第22章:图的基本算法—广度优先搜索和深度优先搜索
- 算法导论-第22章-基本的图算法:强连通分量(深度优先遍历基础上)C++实现
- 算法导论-第22章-基本的图算法-22.5 强连通分量
- 算法导论 第22章 图的基本算法 22.1 图的表示
- 算法导论-第22章-基本的图算法-22.1 图的表示
- 算法导论代码 第22章 图的基本算法