数据结构C++——拓扑排序

文章目录

  • 数据结构C++——拓扑排序
    • 一、前言
    • 二、拓扑排序的概念及作用
    • 三、拓扑排序的实现
      • ①拓扑排序的实现原理
      • ②拓扑排序中FindInDegree()函数的实现
      • ③拓扑排序的代码实现
      • ④完整测试代码
    • 四、总结

一、前言

拓扑排序需要用到邻接表的相关知识,由于笔者在之前的文章中已经介绍过邻接表,此处不再过多赘述,对此部分还不太了解的读者欢迎移步此文章,共同学习!:
数据结构C++——栈
数据结构C++——图的邻接矩阵和邻接表.

二、拓扑排序的概念及作用

(1)有向无环图:一个无环的有向图称作有向无环图,简称DAG图
(2)AOV-网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网,简称AOV-网
(3)拓扑排序:在AOV-网中,不应该出现有向环,因为存在环意味着某项活动应以自己为先决条件。显然, 这是荒谬的。 对给定的 AOV-网应首先判定网中是否存在环。检测的办法是对有向图的顶点进行拓扑排序,若网中所有顶点都在它的拓扑有序序列中, 则该AOV-网中必定不存在环。
所谓拓扑排序就是将AOV-网中所有顶点排成一个线性序列,该序列满足:若在AOV-网中由顶点vi到顶点 vj有一条路径,则在该线性序列中的顶点 Vi必定在顶点Vj之前。
图解算法如下所示

三、拓扑排序的实现

①拓扑排序的实现原理

定义两个辅助数组结构分别用来存放各顶点入度和记录拓扑排序的顶点序号。从第一个无入度的顶点开始,将所有无入度的顶点依次输出并从已有图中摘除,同时将此结点与其他结点所依附的边摘除,最终输出的顶点序列就是拓扑排序序列,此处需要注意的是:有些有向无环图的拓扑排序序列的结果并不唯一

②拓扑排序中FindInDegree()函数的实现

FindInDegree()函数的实现:

FindInDegree()函数的实现思路:
1:定义两层循环遍历整个邻接表
2:定义指向各个边结点的指针,此指针从指向某结点链表的第一个邻接点开始,遍历整个顶点链表,当某边结点邻接点域等于i时,计数变量自增
3:邻接表遍历结束后,将计数变量的值赋予indegree[i]数组单元
void FindInDegree(ALGraph G, int indegree[]) {for (int i = 0; i < G.vexnum; i++) {int cnt = 0;//设置变量存储邻接点域为i的结点个数for (int j = 0; j < G.vexnum; j++) {ArcNode* p = new ArcNode;//定义指向各个边结点的指针p = G.vertices[j].firstarc;while (p) {//当p未指到单个链表的末尾时继续循环if (p->adjvex == i)//当某边结点邻接点域等于i时,计数变量++cnt++;p = p->nextarc;//指针不断向后指}indegree[i] = cnt;//将计数结果保留在indegree数组中}}
}

③拓扑排序的代码实现

拓扑排序的代码实现:

拓扑排序算法思路:
1:求出各结点的入度存入数组indegree中
2:遍历indegree[i]数组,将单元值为0的编号值i进栈
3:将栈顶元素保存在topo数组中,并将此元素出栈。
4:定义指向边结点的指针,使该指针从出栈元素的第一个边结点开始依次向后指,遍历某顶点元素的所有边结点,并将每个边结点对应的indegree数组单元值自减,当indegree单元值为0时,将该边结点邻接点域进栈
5:最后将m和有向图顶点比较,若两者相等,则该图是有向无环图。
Status TopologicalSort(ALGraph G, int topo[]) {//有向图G采用邻接表存储结构//若G无回路,则生成G的一个拓扑排序topo[]并返回OK,否则ERRORFindInDegree(G, indegree);//求出各结点的入度存入数组indegree中SqStack S;InitStack(S);//初始化栈for (int i = 0; i < G.vexnum; i++) {if (!indegree[i]) Push(S, i);//入度为0者进栈}int m = 0;//对输出顶点计数u,初始为0while (!StackEmpty(S)) {int i = 0;Pop(S, i);//将栈顶顶点vi出栈topo[m] = i;//将vi保存在拓扑序列数组topo中++m;//对输出顶点计数ArcNode* p = new ArcNode;p = G.vertices[i].firstarc;//p指向vi的第一个邻接点while (p != NULL) {int k = p->adjvex;//vk为vi的邻接点--indegree[k];//vi的每个邻接点的入度减一if (indegree[k] == 0) Push(S, k);//若入度减为0,则入栈p = p->nextarc;//p指向顶点vi下一个邻接结点}}if (m < G.vexnum) return ERROR;//该有向图有回路else return OK;
}

④完整测试代码

完整的测试代码

#include<iostream>
#include<string>
using namespace std;
#define MVNum 100
#define OK 1
#define ERROR 0
#define MaxInt 100
typedef string VerTexType;
typedef int Status;
typedef int SElemType;
typedef struct{SElemType* base;SElemType* top;int stacksize;
}SqStack;
typedef struct ArcNode {int adjvex;struct ArcNode* nextarc;
}ArcNode;
typedef struct VNode {VerTexType data;ArcNode* firstarc;
}VNode,AdjList[MVNum];
typedef struct {int vexnum, arcnum;AdjList vertices;
}ALGraph;
/*--------拓扑排序辅助数组的存储结构--------*/
int indegree[MVNum];//存放各顶点入度
int topo[MVNum];//记录拓扑序列的顶点编号
Status InitStack(SqStack& S) {S.base = new SElemType[MaxInt];if (!S.base) return ERROR;S.top = S.base;S.stacksize = MaxInt;return OK;
}
Status StackEmpty(SqStack S) {if (S.top == S.base) return OK;return ERROR;
}
Status Push(SqStack& S, SElemType e) {if (S.top - S.base == S.stacksize) return ERROR;*S.top = e;S.top++;return OK;
}
Status Pop(SqStack& S, SElemType& e) {if (S.base == S.top) return ERROR;S.top--;e = *S.top;return OK;
}
int LocateVex(ALGraph G, VerTexType v) {for (int i = 0; i < G.vexnum; i++) {if (G.vertices[i].data == v)return i;}return -1;
}
void CreateUDG(ALGraph& G) {cin >> G.vexnum >> G.arcnum;for (int i = 0; i < G.vexnum; i++) {cin >> G.vertices[i].data;G.vertices[i].firstarc = NULL;//初始化表头结点的指针域为NULL}for (int k = 0; k < G.arcnum; k++) {VerTexType v1, v2;cin >> v1 >> v2;int i = LocateVex(G, v1);int j = LocateVex(G, v2);ArcNode* p1 = new ArcNode;p1->adjvex = j;p1->nextarc = G.vertices[i].firstarc;G.vertices[i].firstarc = p1;}
}
void FindInDegree(ALGraph G, int indegree[]) {for (int i = 0; i < G.vexnum; i++) {int cnt = 0;//设置变量存储邻接点域为i的结点个数for (int j = 0; j < G.vexnum; j++) {ArcNode* p = new ArcNode;//定义指向各个边结点的指针p = G.vertices[j].firstarc;while (p) {//当p未指到单个链表的末尾时继续循环if (p->adjvex == i)//当某边结点邻接点域等于i时,计数变量++cnt++;p = p->nextarc;//指针不断向后指}indegree[i] = cnt;//将计数结果保留在indegree数组中}}
}
Status TopologicalSort(ALGraph G, int topo[]) {//有向图G采用邻接表存储结构//若G无回路,则生成G的一个拓扑排序topo[]并返回OK,否则ERRORFindInDegree(G, indegree);//求出各结点的入度存入数组indegree中SqStack S;InitStack(S);//初始化栈for (int i = 0; i < G.vexnum; i++) {if (!indegree[i]) Push(S, i);//入度为0者进栈}int m = 0;//对输出顶点计数u,初始为0while (!StackEmpty(S)) {int i = 0;Pop(S, i);//将栈顶顶点vi出栈topo[m] = i;//将vi保存在拓扑序列数组topo中++m;//对输出顶点计数ArcNode* p = new ArcNode;p = G.vertices[i].firstarc;//p指向vi的第一个邻接点while (p != NULL) {int k = p->adjvex;//vk为vi的邻接点--indegree[k];//vi的每个邻接点的入度减一if (indegree[k] == 0) Push(S, k);//若入度减为0,则入栈p = p->nextarc;//p指向顶点vi下一个邻接结点}}if (m < G.vexnum) return ERROR;//该有向图有回路else return OK;
}
/*输出拓扑排序后的结果*/
void PrintResult(ALGraph G) {if (TopologicalSort(G, topo)) {for (int i = 0; i < G.vexnum; i++) {cout << G.vertices[topo[i]].data << " ";}}
}
int main() {ALGraph G;CreateUDG(G);PrintResult(G);return 0;
}
输入:
6 8
v1 v2 v3 v4 v5 v6
v1 v2
v1 v3
v1 v4
v3 v2
v3 v5
v4 v5
v6 v4
v6 v5

输入数据构造的有向无环图

由于去掉一些无入度的结点后,此时可能有多个结点都无入度,可从中任选一个继续进行。因此,有些有向无环图的拓扑排序序列的结果并不唯一

输出:
v6 v1 v3 v2 v4 v5

四、总结

以上为笔者对于拓扑排序的一些见解,希望初学者都能有所收获,有技术不到位的地方,还望各位大佬指正。
同时,笔者的个人主页还有数据结构中其他部分的一些见解与分析,后续数据结构的相关知识还将陆续更新,欢迎大家访问且共同学习!

数据结构C++——拓扑排序相关推荐

  1. 数据结构-图论-拓扑排序模板题(hdu3342)(poj1270)(hdu4857)

    dfs与bfs的很直接的应用就是拓扑排序. 拓扑排序如果用数组来模拟链表进行操作,既解决了稀疏图的空间问题,又解决了用链表进行操作麻烦的问题 但是拓扑排序并不是数字大小之间的排序,而是某些事情之间的顺 ...

  2. 【数据结构】拓扑排序

    如果一个有向图中没有包含简单的回路,这样的图为有向无环图. 图中的顶点代表事件(活动),图中的有向边说明了事件之间的先后关系.这种用顶点表示活动,用弧表示活动时间的优先关系的有向图称为顶点表示活动的网 ...

  3. 大话数据结构:拓扑排序

    基础介绍 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G), ...

  4. 教学计划编制问题(数据结构 有向图 拓扑排序)

    本文对以下教学计划编制问题的解决作出实现,主要使用c语言(带一点cpp),开发环境为codeblocks 17.12,希望对各位读者有所帮助.(源码和数据文件可在主页获取,数据文件需要和exe在同一目 ...

  5. 【数据结构】拓扑排序 Kahn版和DFS版

    Kahn版 TopologicalSort: const int NUM = 10; vector<int> v[10],ans_path;//其中v[]是用邻接表存储的一个图. int ...

  6. 有向图的拓扑排序的理解和简单实现(Java)

    如果图中存在环(回路),那么该图不存在拓扑排序,在这里我们讨论的都是无环的有向图. 什么是拓扑排序 一个例子 对于一部电影的制作过程,我们可以看成是一个项目工程.所有的工程都可以分为若干个" ...

  7. AOV网--拓扑排序(必须是一个有向无环图)

     特点: 1.  AOV网用顶点表示活动,用弧表示活动之间优先关系, 2. AOV网中的弧表示活动之间存在某种制约关系, 3. AOV网中不能出现回路(如果有回路,说明某项活动以自己作为先决条件,不允 ...

  8. aov建立Java模拟,数据结构之---C语言实现拓扑排序AOV图

    //有向图的拓扑排序 //杨鑫 #include #include #include #define MAX_NAME 3 #define MAX_VERTEX_NUM 20 typedef int ...

  9. 【数据结构】图的应用(普利姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法、拓扑排序)

    最小生成树 什么是最小生成树 是一棵树 - 无回路 - |V|个顶点一定有|V|-1条边 是生成树 - 包含全部顶点 - |V|-1条边全在图里 贪心算法 什么是"贪":每一步都要 ...

最新文章

  1. 动图|帮你一次性搞清楚 40种传感器工作原理
  2. 晶体管参数在实际使用中的意义
  3. ios 圆形旋转菜单_iOS高级动画:圆形树展开收起动画
  4. 【Android 逆向】Dalvik 函数抽取加壳 ( Dalvik 下的函数指令抽取与恢复 | dex 函数指令恢复时机点 | 类加载流程 : 加载、链接、初始化 )
  5. 【机器学习PAI实践七】文本分析算法实现新闻自动分类
  6. XML解析——Jsoup解析器
  7. 网口扫盲二:Mac与Phy组成原理的简单分析(转)
  8. android studio电影院选座,8排电影院选座最佳位置
  9. Oracle中随机抽取N条记录,使用Oracle分析函数随机抽取N条记录
  10. python配什么数据库_python中常见数据库有哪些
  11. 空心等腰三角形java_java打印输出任意大小的等腰三角形,实心菱形,空心菱形,平行四边形...
  12. Android Studio真机测试失败-----''No target device found
  13. 【Rollo的Python之路】比较运算符
  14. 文档加密图纸加密方案之沙盒
  15. 图像处理R包magick学习笔记
  16. 网络编程 2 套接字socket
  17. 爬虫处理payload请求
  18. 尼得科薄型横向线性Slider系列震动马达
  19. 想学linux需要的电脑配置相关
  20. 犯罪嫌疑人X的献身和三体

热门文章

  1. 【ChatGPT对当代大学生的影响】
  2. android contentprovider原理,ContentProvider原理分析
  3. 论文笔记11:Understanding the seasonal variations of land surface temperature in Nanjing urban area based
  4. 掌握了c语言就能够编程,C语言编程学习-C语言编程学习app-最火手机站
  5. oracle 闪存查询,【oracle相关】关于数据闪存恢复的说明
  6. VR全景创业加盟全景平台有哪些优势?给哪些支持?
  7. 让策划人员一键生成创意方案,这款 AI 产品是如何做到的?
  8. 简单介绍线程和进程区别
  9. 为什么“数据驱动”只属于那些“天生的数字公司”,传统企业却只有束缚?...
  10. BCL easyConverter SDK