拓扑排序(二)之 C++详解
本章是通过C++实现拓扑排序。
目录
1. 拓扑排序介绍
2. 拓扑排序的算法图解
3. 拓扑排序的代码说明
4. 拓扑排序的完整源码和测试程序转载请注明出处:http://www.cnblogs.com/skywang12345/
更多内容:数据结构与算法系列 目录
拓扑排序介绍
拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。
这样说,可能理解起来比较抽象。下面通过简单的例子进行说明!
例如,一个项目包括A、B、C、D四个子部分来完成,并且A依赖于B和D,C依赖于D。现在要制定一个计划,写出A、B、C、D的执行顺序。这时,就可以利用到拓扑排序,它就是用来确定事物发生的顺序的。
在拓扑排序中,如果存在一条从顶点A到顶点B的路径,那么在排序结果中B出现在A的后面。
拓扑排序的算法图解
拓扑排序算法的基本步骤:
1. 构造一个队列Q(queue) 和 拓扑排序的结果队列T(topological);
2. 把所有没有依赖顶点的节点放入Q;
3. 当Q还有顶点的时候,执行下面步骤:
3.1 从Q中取出一个顶点n(将n从Q中删掉),并放入T(将n加入到结果集中);
3.2 对n每一个邻接点m(n是起点,m是终点);
3.2.1 去掉边<n,m>;
3.2.2 如果m没有依赖顶点,则把m放入Q;
注:顶点A没有依赖顶点,是指不存在以A为终点的边。
以上图为例,来对拓扑排序进行演示。
第1步:将B和C加入到排序结果中。
顶点B和顶点C都是没有依赖顶点,因此将C和C加入到结果集T中。假设ABCDEFG按顺序存储,因此先访问B,再访问C。访问B之后,去掉边<B,A>和<B,D>,并将A和D加入到队列Q中。同样的,去掉边<C,F>和<C,G>,并将F和G加入到Q中。
(01) 将B加入到排序结果中,然后去掉边<B,A>和<B,D>;此时,由于A和D没有依赖顶点,因此并将A和D加入到队列Q中。
(02) 将C加入到排序结果中,然后去掉边<C,F>和<C,G>;此时,由于F有依赖顶点D,G有依赖顶点A,因此不对F和G进行处理。
第2步:将A,D依次加入到排序结果中。
第1步访问之后,A,D都是没有依赖顶点的,根据存储顺序,先访问A,然后访问D。访问之后,删除顶点A和顶点D的出边。
第3步:将E,F,G依次加入到排序结果中。
因此访问顺序是:B -> C -> A -> D -> E -> F -> G
拓扑排序的代码说明
拓扑排序是对有向无向图的排序。下面以邻接表实现的有向图来对拓扑排序进行说明。
1. 基本定义
#define MAX 100
// 邻接表
class ListDG
{
private: // 内部类
// 邻接表中表对应的链表的顶点
class ENode
{
int ivex; // 该边所指向的顶点的位置
ENode *nextEdge; // 指向下一条弧的指针
friend class ListDG;
};
// 邻接表中表的顶点
class VNode
{
char data; // 顶点信息
ENode *firstEdge; // 指向第一条依附该顶点的弧
friend class ListDG;
};
private: // 私有成员
int mVexNum; // 图的顶点的数目
int mEdgNum; // 图的边的数目
VNode *mVexs; // 图的顶点数组
public:
// 创建邻接表对应的图(自己输入)
ListDG();
// 创建邻接表对应的图(用已提供的数据)
ListDG(char vexs[], int vlen, char edges[][2], int elen);
~ListDG();
// 深度优先搜索遍历图
void DFS();
// 广度优先搜索(类似于树的层次遍历)
void BFS();
// 打印邻接表图
void print();
// 拓扑排序
int topologicalSort();
private:
// 读取一个输入字符
char readChar();
// 返回ch的位置
int getPosition(char ch);
// 深度优先搜索遍历图的递归实现
void DFS(int i, int *visited);
// 将node节点链接到list的最后
void linkLast(ENode *list, ENode *node);
};
(01) ListDG是邻接表对应的结构体。 mVexNum是顶点数,mEdgNum是边数;mVexs则是保存顶点信息的一维数组。
(02) VNode是邻接表顶点对应的结构体。 data是顶点所包含的数据,而firstEdge是该顶点所包含链表的表头指针。
(03) ENode是邻接表顶点所包含的链表的节点对应的结构体。 ivex是该节点所对应的顶点在vexs中的索引,而nextEdge是指向下一个节点的。
2. 拓扑排序
/*
* 拓扑排序
*
* 返回值:
* -1 -- 失败(由于内存不足等原因导致)
* 0 -- 成功排序,并输入结果
* 1 -- 失败(该有向图是有环的)
*/
int ListDG::topologicalSort()
{
int i,j;
int index = 0;
int head = 0; // 辅助队列的头
int rear = 0; // 辅助队列的尾
int *queue; // 辅组队列
int *ins; // 入度数组
char *tops; // 拓扑排序结果数组,记录每个节点的排序后的序号。
ENode *node;
ins = new int[mVexNum];
queue = new int[mVexNum];
tops = new char[mVexNum];
memset(ins, 0, mVexNum*sizeof(int));
memset(queue, 0, mVexNum*sizeof(int));
memset(tops, 0, mVexNum*sizeof(char));
// 统计每个顶点的入度数
for(i = 0; i < mVexNum; i++)
{
node = mVexs[i].firstEdge;
while (node != NULL)
{
ins[node->ivex]++;
node = node->nextEdge;
}
}
// 将所有入度为0的顶点入队列
for(i = 0; i < mVexNum; i ++)
if(ins[i] == 0)
queue[rear++] = i; // 入队列
while (head != rear) // 队列非空
{
j = queue[head++]; // 出队列。j是顶点的序号
tops[index++] = mVexs[j].data; // 将该顶点添加到tops中,tops是排序结果
node = mVexs[j].firstEdge; // 获取以该顶点为起点的出边队列
// 将与"node"关联的节点的入度减1;
// 若减1之后,该节点的入度为0;则将该节点添加到队列中。
while(node != NULL)
{
// 将节点(序号为node->ivex)的入度减1。
ins[node->ivex]--;
// 若节点的入度为0,则将其"入队列"
if( ins[node->ivex] == 0)
queue[rear++] = node->ivex; // 入队列
node = node->nextEdge;
}
}
if(index != mVexNum)
{
cout << "Graph has a cycle" << endl;
delete queue;
delete ins;
delete tops;
return 1;
}
// 打印拓扑排序结果
cout << "== TopSort: ";
for(i = 0; i < mVexNum; i ++)
cout << tops[i] << " ";
cout << endl;
delete queue;
delete ins;
delete tops;
return 0;
}
说明:
(01) queue的作用就是用来存储没有依赖顶点的顶点。它与前面所说的Q相对应。
(02) tops的作用就是用来存储排序结果。它与前面所说的T相对应。
拓扑排序的完整源码和测试程序
拓扑排序(二)之 C++详解的更多相关文章
- 拓扑排序(三)之 Java详解
前面分别介绍了拓扑排序的C和C++实现,本文通过Java实现拓扑排序. 目录 1. 拓扑排序介绍 2. 拓扑排序的算法图解 3. 拓扑排序的代码说明 4. 拓扑排序的完整源码和测试程序 转载请注明出处 ...
- MySQL慢查询(二) - pt-query-digest详解慢查询日志 pt-query-digest 慢日志分析
随笔 - 66 文章 - 0 评论 - 19 MySQL慢查询(二) - pt-query-digest详解慢查询日志 一.简介 pt-query-digest是用于分析mysql慢查询的一个工具,它 ...
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- Java进阶(三十二) HttpClient使用详解
Java进阶(三十二) HttpClient使用详解 Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们 ...
- Spring Boot 启动(二) 配置详解
Spring Boot 启动(二) 配置详解 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Boot 配置 ...
- Android ADB命令教程二——ADB命令详解
Android ADB命令教程二——ADB命令详解 转载▼ 原文链接:http://www.tbk.ren/article/249.html 我们使用 adb -h 来看看,adb命令里面 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- [hihoCoder] 第四十八周: 拓扑排序·二
题目1 : 拓扑排序·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒.这事在校内BBS上立刻引起了大家的讨论,当 ...
- hiho一下 第四十八周 拓扑排序·二【拓扑排序的应用 + 静态数组 + 拓扑排序算法的时间优化】
题目1 : 拓扑排序·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho所在学校的校园网被黑客入侵并投放了病毒.这事在校内BBS上立刻引起了大家的讨论,当 ...
随机推荐
- 使用属性android:onClick,出现异常NoSuchMethodException
在Activity中注册点击事件有两种方式,setOnClickListener或在xml中设置控件的android:onClick="gotoSecond"属性,在Activit ...
- [XAF] Simplifying integration of custom controls bound to data from XAF application database
ASP.NET: http://www.screencast.com/t/OHhcHD9vy WinForms: http://www.screencast.com/t/8M8K4eskkYO9
- css布局模型
---恢复内容开始--- 在清楚了CSS盒模型的基本概念,盒模型类型,我们就可以深入探讨网页布局的基本模型了.布局模型与盒模型一样都是CSS最基本,最核心的概念.但布局模型是建立在盒型基础之上,又不同 ...
- Reactnative 随笔一
---恢复内容开始--- 1.ReactDOM.render() React的最基本方法,用于将模板转为HTML语言,并插入指定的DOM节点 将h标签插入example节点 2.HTML语言直接 ...
- 字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串
Visual Studio提供的Dotfuscator保护程序,可以对用户代码中包含的字符串进行加密.比如下面的例子,为了找到这个程序的注册算法,用.NET Reflector加载程序集后,发现代码中 ...
- hadoop使用问题
前提 环境 ubuntu 安装hadoop 已经有一段时间 1.启动的时候提示 Connection reset by peer 这个查看日志,里面有说 ssh里面某个文件的权限太大 这个ssh里修改 ...
- ENode 1.0 - Command Service设计思路
开源地址:https://github.com/tangxuehua/enode 上一篇文章,介绍了enode框架的物理部署思路.本文我们再简单分析一下Command Service的API设计: C ...
- 开发者必知的几款App快速开发工具
“我有一个好创意,就差一个CTO……” ,这是今年炒的比较火的一句话. “原生APP开发难度大,周期长,成本高,还没上线市场已经被占领了.这个有没有解决方案?” “APP版本迭代更新,都是企业的一道难 ...
- CocoSocket开源下载与编写经验分享
CocoSocket分享 cocos2dx 3.1都出了,但依然没有发现与它原生的SOCKET支持,于是,这几天在家,手工撸了一个. 目前版本对IOS,ANDROID,WINDOWS支持良好.且为异步 ...
- springmvc下实现登录验证码功能
总体思路,简单讲,就是后台生成图片同时将图片信息保存在session,前端显示图片,输入验证码信息后提交表单到后台,取出存放在session里的验证码信息,与表单提交的验证码信息核对. 点击验证码图片 ...