对于有向无环图G中的任意结点u,v,它们之间的关系必然是以下三种之一:

(1)假设结点u是结点v的祖先,则在调用DFS访问u的过程中,必然会在这个过程结束之前递归地对v调用DFS访问,即v的DFS函数结束时间现语u的DFS结束时间。从而可以考虑在DFS调用过程中设定一个时间标记,在DFS调用结束时,对个结点计时。因此,祖先的结束时间大于子孙的结束时间。

(2)若结点u是结点v的子孙,则v为u的祖先,按照上述思路,v的结束时间大于u的结束时间。

(3) 若u和v没有关系,则u和v在拓扑序列中的关系任意。从而按照结束时间从大到小,可以得到一个拓扑序列。

下面给出利用DFS求各节点结束时间的代码。至于拓扑序列,将结束时间从大到小排序即可得到。(实际上和深度优先遍历算法完全相同,只不过加入了时间变量。
假设图和邻接表是以下这样子滴~~~~:

代码实现如下:

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;#define MAX_VERTEX_NUM 10
typedef char VertexType;int timeBack = 0;//全局变量,记录各顶点的退出时间
int finishTime[MAX_VERTEX_NUM];
typedef struct ArcNode
{int adjvex;//边/弧指向哪个结点struct ArcNode* nextarc;//指向下一条弧的指针
} ArcNode;//边结点
typedef struct VNode
{VertexType data;//顶点信息ArcNode* firstarc;//第一条边/弧
} VNode, AdjList[MAX_VERTEX_NUM];
//邻接表
typedef struct
{AdjList vertices;int vexnum, arcnum;
} ALGraph;
bool visited[MAX_VERTEX_NUM];//标记访问数组//创建邻接表
void CreateAdj(ALGraph*& G, int n)
{int i;G = (ALGraph*)malloc(sizeof(ALGraph));for (i = 0; i < n; i++){G->vertices[i].firstarc = NULL;}//初始化顶点数和边数,根据后面插入的邻接点动态添加边数G->vexnum = n;G->arcnum = 0;
}//将边结点插入到某个顶点表的边表中,默认拓扑排序为有向无环图,这里只考虑有向图,x为起点,y为终点
void InsertAdj(ALGraph* G, int x, int y, int& e)
{//头插法ArcNode* p;//防止非法输入if (x < 0 || x >= MAX_VERTEX_NUM || y < 0 || y >= MAX_VERTEX_NUM){printf("插入失败!!!");}p = (ArcNode*)malloc(sizeof(ArcNode));p->adjvex = y;p->nextarc = G->vertices[x].firstarc;G->vertices[x].firstarc = p;e = ++G->arcnum;
}//输出邻接表
void DispAdj(ALGraph* G)
{int i;ArcNode* p;for (i = 0; i < G->vexnum; i++){p = G->vertices[i].firstarc;printf("%3d号顶点:\t", i);while (p != NULL){printf("%3d->", p->adjvex);p = p->nextarc;}printf("\t空\n");}
}//销毁邻接表
void DestroyAdj(ALGraph*& G)
{int i;ArcNode* pre, * p;for (i = 0; i < G->vexnum; i++)//扫描所有边表{pre = G->vertices[i].firstarc;if (pre != NULL){p = pre->nextarc;while (p != NULL){free(pre);pre = p;p = p->nextarc;}free(pre);}}free(G);
}//求图G中顶点x的第一个邻接点,若有则返回顶点号,若x没有邻接点或图中不存在x,则返回-1
int FirstNeighbor(ALGraph* G, int x)
{ArcNode* p;if (x >= MAX_VERTEX_NUM || x < 0) //限定顶点数值的范围为0~MAX_VERTEX_NUM -1{return -1;}p = G->vertices[x].firstarc;if (p == NULL){return -1;}return p->adjvex;
}//假设图G中顶点y是x的一个邻接点,返回除了y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
int NextNeighbor(ALGraph* G, int x, int y)
{int w;ArcNode* p;p = G->vertices[x].firstarc;while (p != NULL){w = p->adjvex;if (p->nextarc != NULL && (w == y))//说明当前访问的邻接点是y并且有下一个邻接点{return p->nextarc->adjvex;}p = p->nextarc;}//若遍历完但while循环中的语句还没有任何返回,就执行最后的返回return -1;
}
void visit(int v)
{printf("%3d\t", v);
}
void DFS(ALGraph* G, int v)
{visited[v] = true;visit(v);for (int w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)){if (!visited[w]) //w为u的尚未访问的邻接结点{DFS(G, w);}//if}//fortimeBack = timeBack + 1;//先退出DFS的函数时间最小finishTime[v] = timeBack;
}bool DFSTraverse(ALGraph* G,int v)
{//对图G进行遍历,访问函数为visit()for (int v = 0; v < G->vexnum; ++v){visited[v] = false;//初始化访问标记数组finishTime[v] = 0;//初始化每个顶点的退出时间}//本代码表示是从v = 0开始遍历/*for (int v = 0; v < G->vexnum; ++v){if (!visited[v]){DFS(G, v);}}*/DFS(G, v);
}int cmp(const pair<string, int>& x, const pair<string, int>& y)
{return x.second >= y.second;
}
void sortMapByValue(map<string, int>& tMap, vector<pair<string, int> >& tVector)
{for (map<string, int>::iterator curr = tMap.begin(); curr != tMap.end(); curr++)tVector.push_back(make_pair(curr->first, curr->second));sort(tVector.begin(), tVector.end(), cmp);
}int main()
{int n = 5;//顶点数为4int e = 0;//记录边数ALGraph* G;CreateAdj(G, n);InsertAdj(G, 0, 2, e);InsertAdj(G, 0, 1, e);InsertAdj(G, 1, 3, e);InsertAdj(G, 1, 2, e);InsertAdj(G, 2, 3, e);/*InsertAdj(G, 1, 0, e);InsertAdj(G, 1, 3, e);InsertAdj(G, 0, 4, e);InsertAdj(G, 3, 4, e);InsertAdj(G, 4, 2, e);*/printf("图中共有%d个顶点,%d条边", n, e);printf("图G:\n");DispAdj(G);DFSTraverse(G,0);printf("各顶点对应的退出时间: \n");map<string, int> tMap;vector<pair<string, int>> tVector;for (int i = 0; i < G->vexnum; i++){tMap.insert(pair<string, int>(to_string(i) + "号顶点", finishTime[i]));}sortMapByValue(tMap, tVector);printf("\n");//拓扑序列printf("拓扑序列如下: ");for (int i = 0; i < tVector.size(); i++){cout << tVector[i].first << "(退出递归所需时间:" << tVector[i].second << ")" << "----->";}cout << endl;system("pause");DestroyAdj(G);//销毁邻接表
}

基于DFS的拓扑排序算法实现相关推荐

  1. 算法导论:dfs深度优先搜索算法及基于dfs的拓扑排序以及宽度优先搜索算法bfs

    1.dfs深度优先搜索算法 算法导论中是通过三种标记颜色来介绍dfs的,white代表还没被搜过,grey代表被搜了一些,还没结束,white表示已经搜索完成的状态. c/c++复现dfs代码 #in ...

  2. 【zz】如何去理解 拓扑排序算法

    from http://www.cnblogs.com/shanyou/archive/2006/11/16/562861.html 查看Castle的代码,在Castle.Core中内部的数据结构采 ...

  3. vant coupon 时间戳如何计算_计软考研双日练 | 如何计算拓扑排序算法的时间复杂度?...

    ☝☝☝ 软件工程考研独家平台 撰稿 | 康康哥 编辑 | 丽丽姐 本文由懂计算机.软件工程的博士师哥原创 双日练:NO.20200610 若将n个顶点e条弧的有向图采用邻接表存储,则拓扑排序算法的时间 ...

  4. JavaScript实现topologicalSort拓扑排序算法(附完整源码)

    JavaScript实现topologicalSort拓扑排序算法(附完整源码) Comparator.js完整源代码 LinkedListNode.js完整源代码 LinkedList.js完整源代 ...

  5. C++实现topological sort拓扑排序算法(附完整源码)

    C++实现topological sort拓扑排序算法 C++实现topological sort拓扑排序算法完整源码(定义,实现,main函数测试) C++实现topological sort拓扑排 ...

  6. C++使用kahn实现topological sort拓扑排序算法(附完整源码)

    C++使用kahn实现topological sort拓扑排序算法 C++使用kahn实现topological sort拓扑排序算法完整源码(定义,实现,main函数测试) C++使用kahn实现t ...

  7. 邻接表存储 - 拓扑排序算法

    拓扑排序:用下面的例子介绍------> ---------------------------------------------------------------------------- ...

  8. python 拓扑排序 dfs bfs_拓扑排序的DFS和BFS

    博主以前有一个疑问,DFS和BFS各自的适用范围是?我想你今天看了这篇文章之后会有一个判断! BFS 数据结构与算法分析:c语言描述(p217) 已经存在一个Indgree入度数组(indgree[v ...

  9. 【恋上数据结构】图代码实现、BFS、DFS、拓扑排序

    图代码实现 图的基础代码 顶点Vertex 边Edge 添加边addEdge 删除边removeEdge 删除点removeVertex 完整源码 图的遍历 广度优先搜索(Breadth First ...

  10. [jzoj 4246] 【五校联考6day2】san {spfa+dfs/spfa+拓扑排序+dp}

    题目 Description 小明经常去N 个地点,其中有些地点之间有直接的无向道路(共M 条这样的道路),可以直接互相到达,这些道路的长短不一.由于小明对这些道路都很熟悉,无论起点和终点在哪里,总能 ...

最新文章

  1. ajax异步后台存放购物车表,jQuery购物车插件jsorder用法(支持后台处理程序直接转换成DataTable处理)...
  2. 【Android 逆向】Android 进程注入工具开发 ( SO 进程注入环境及 root 权限获取 | 进程注入时序分析 )
  3. Tomcat——设置管理员的用户名和密码
  4. python语言与c语言相比在分支结构上有什么不同_大工20春 C/C 语言程序设计 在线作业3 - 百度文库...
  5. Delphi XE7 Update1修正列表
  6. CodeForces - 1200E Compress Words(字符串哈希)
  7. PopsTabView--filter容器
  8. 高斯滤波器是低通还是高通_经典模拟滤波器仍值得研究吗?
  9. uv转化率多少正常_宣城UV光解设备价格多少-低价供应
  10. oracle 查看日志组切换状态_【DB笔试面试800】在Oracle中,归档和非归档模式之间的不同点是什么?它们各自的优缺点是什么?...
  11. 当电子工程师十余年,感慨万千
  12. 图论,回路,旅行商、邮递员问题。
  13. L9110H电机驱动模块-FPGA
  14. 关键词搜索-免费搜索关键词排名软件
  15. C++ 游戏服务器开发有什么推荐的学习资料或者书籍?
  16. 色盲悖论_关于被色盲
  17. 三星拿出了四摄手机,可惜诚意不足,挑战国产手机成奢望
  18. 文墨绘学任何事物都是发展变化的
  19. Xshell6|Xftp6 要继续使用此程序,您必须应用最新的更新或使用新版本
  20. 【MySQL】联合索引的使用

热门文章

  1. 内核仿阿里巴巴小说网站源码 PC端+WAP端
  2. 汽车门店管理系统 php,大型汽车4s店维修管理系统多门店版(源码+数据库+截图)...
  3. cad 2019 mac安装破解详细图文教程
  4. Android 解决Dialog 样式的Activity 半透明背景失效问题
  5. Spring中的ref和depends-on区别
  6. 单片机实验计数显示器C语言代码,单片机 计数显示器实验报告
  7. IC基础知识7-数据选择器
  8. java定时统计_java 定时任务每日晚上凌晨执行数据统计
  9. 使用S32DS集成MCAL
  10. 用冰封服务器安装系统,用冰封PE来安装windows纯净版系统