文章目录

  • 什么是拓扑排序
  • 拓扑排序的过程
  • 拓扑排序的实现
    • 采用邻接矩阵实现
    • 运行结果:
    • 采用邻接表实现
    • 运行结果:

什么是拓扑排序

拓扑排序经常用于完成有依赖关系的任务的排序。
举个例子:
一个软件工程专业的学生必须学习系列的基本课程,其中有些课程是基础课,独立于其他课程,而另一些课程必须先学完先修课程才可以开始后序课程。这个关系可以用有向图表示。

学生必须按照拓扑有序的顺序来安排学习计划,这样才能保证学习任何一门课程时其先修课程已经学过。

拓扑排序的过程

  • 在有向图中找一个无前驱的顶点且输出。
  • 删除该顶点指向另外顶点的弧。
  • 重复以上两步,直至不存在没有前驱的点
  • 若输出的顶点数小于有向图中的顶点数,则说明图中存在环。否则输出的序列即为拓扑排序。

拓扑排序的实现

需要一个辅助数组indegree[i]来存储各个顶点的入度。

  • 采用邻接矩阵实现

#include<iostream>
#include<stdlib.h>
#include<stack>
#include<queue>
using namespace std;#define MVNum 10//最大顶点数
#define MAXINT 32768//表示极大值 typedef int arcType;
typedef char vertexType;typedef struct MNode{vertexType vertex[MVNum];  //存储顶点 arcType Arc[MVNum][MVNum];   //邻接矩阵,存储边 int vexnum,arcnum;
}GraphNode,*Graph;int indegree[MVNum]={0};     //记录各个顶点的入度 int Init(Graph &G){G=(GraphNode *)malloc(sizeof(GraphNode));G->vexnum=0;G->arcnum=0;if(G) return 1;else cout<<"初始化出错!"<<endl;return 0;
}void FindPos(Graph G,char a,char b,int &pos1,int &pos2){//查找位置 int i=0;pos1=-1;pos2=-1;for(int i=0;i<G->vexnum;i++){if(G->vertex[i]==a){pos1=i;continue;}else if(G->vertex[i]==b){pos2=i;continue;}}
}void CreateDG(Graph G)         //创建有向图
{int num=0,                    //控制输入顶点数 pos1,pos2,                //确认顶点位置 i,j;char a,b,ch;                   //顶点 for(int i=0;i<MVNum;i++){                //初始化 for(int j=0;j<MVNum;j++){G->Arc[i][j]=0;}}cout<<"请输入顶点,以#结束"<<endl;cin>>ch;while(ch!='#'&&num<10){G->vertex[num]=ch;cin>>ch;num++;} G->vexnum=num;cout<<"请输入对应的弧(ab与ba是方向相反的边),以##结束"<<endl;cin>>a>>b;while(a!='#'&&b!='#'){cout<<a<<"->"<<b<<endl;FindPos(G,a,b,pos1,pos2);cout<<"位置a:"<<pos1<<"位置b:"<<pos2<<endl;if(pos1!=-1&&pos2!=-1){G->Arc[pos1][pos2]=1;G->arcnum++;indegree[pos2]++; }cin>>a>>b;            }
}void topo(Graph G)
{stack<int>s;queue<int>q;int i,temp;for(i=0;i<G->vexnum;i++){if(!indegree[i]) s.push(i);       }while(!s.empty()){temp=s.top();q.push(temp);s.pop();for(i=0;i<G->vexnum;i++){    if(G->Arc[temp][i]){indegree[i]--;           if(indegree[i]==0) s.push(i);} }    } if(q.size()<G->vexnum) printf("该有向图有回路"); else{while(!q.empty()){printf("%c ",G->vertex[q.front()]);q.pop();}}
}void show(Graph G){for(int i=0;i<G->vexnum;i++){for(int j=0;j<G->vexnum;j++){cout<<G->Arc[i][j]<<" ";}cout<<endl;}
}int main(){Graph G = NULL;Init(G);CreateDG(G);topo(G);return 0;
}
  • 运行结果:


返回顶部

  • 采用邻接表实现

#include <iostream>
#include<stack>
#include<queue>
using namespace std;#define MVNum 10                                        //最大顶点信息
int indegree[MVNum]={0};typedef char VerTexType;
typedef int OtherInfo;//----------图的邻接表存储表示-----------
typedef struct ArcNode {                                //边结点int adjvex;                                            //该边所指向顶点的位置struct ArcNode *nextarc;                            //指向下一条边的指针OtherInfo info;                                      //和边相关的信息}ArcNode;typedef struct VNode {VerTexType data;                                    //顶点信息ArcNode *fristarrc;                                   //指向第一条依附该顶点的边 } VNode,AdjList[MVNum];typedef struct {AdjList vertices;                                 // 邻接表int vexnum;                                         //图的当前顶点数int arcnum;                                          //图的当前边数
}ALGraph;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 CreateDG(ALGraph &G) {                                //采用邻接表表示法,创建有向图Gint i, k;cout << "请输入总顶点数和总边数:"  ;               //输出总顶点数,总边数cin >> G.vexnum >> G.arcnum;cout << endl;cout << "请输入顶点:" << endl;for (i = 0 ; i < G.vexnum; i++) {                 //输入各点,构建表头结点cout << "请输入第" << (i + 1) << "个顶点的名称:";cin >> G.vertices[i].data;G.vertices[i].fristarrc = NULL;                 //初始化表头结点的指针域为NULL}cout << endl;cout << "请输入一条边依附的顶点:" <<endl;for (k = 0; k < G.arcnum; k++) {VerTexType v1, v2;int i, j;cout << "请输入第" << (k+1) << "条边依附的顶点";cin >> v1 >> v2;                               //输入一条边依附的两个顶点i = LocateVex(G, v1);                            //确定v1和v2在G中的位置,j = LocateVex(G, v2);                           //即顶点在G.vertices(邻接表)中的序号indegree[j]++;                                       ArcNode *p1 = new ArcNode;                     //生成一个新的边结点*p1p1->adjvex = j;                                   //邻接点序号为jp1->nextarc = G.vertices[i].fristarrc; G.vertices[i].fristarrc = p1;                  //将新节点*p1插入vi的边表//      ArcNode *p2 = new ArcNode;                     //生成另一个对称的新的边结点*p2
//        p2->adjvex = i;                                   //邻接点序号为i
//      p2->nextarc = G.vertices[j].fristarrc;
//      G.vertices[j].fristarrc = p2;                  //将新结点*p2插入顶点Vj的边表}
}void topo(ALGraph G)
{stack<int>s;queue<int>q;ArcNode *p=NULL;int i,k,temp;   for(i=0;i<G.vexnum;i++){if(!indegree[i]) s.push(i);       }while(!s.empty()){temp=s.top();q.push(temp);s.pop();p=G.vertices[temp].fristarrc;while(p!=NULL){k=p->adjvex;indegree[k]--;                    if(indegree[k]==0) s.push(k);p=p->nextarc;}    }  if(q.size()<G.vexnum) printf("该有向图有回路"); else{while(!q.empty()){printf("%c ",G.vertices[q.front()].data);q.pop();}}
}int main(){ALGraph G;CreateDG(G);int i;cout << endl;for (i = 0; i < G.vexnum; i++) {VNode temp = G.vertices[i];                    //将G的顶点信息付给tempArcNode *p = temp.fristarrc;                //将顶点信息temp中的边信息给pif ( p ==  NULL){cout << G.vertices[i].data;cout << endl;}else {cout << temp.data;while (p){cout << "->";cout << p->adjvex;p = p->nextarc;}
//          if(!p){
//              cout<<"->^";
//          } }cout << endl;}topo(G);return 0;
}
  • 运行结果:


从上面可以看出拓扑排序序列不一定相同,只要满足先序在后序前面即可。
返回顶部

图的应用--拓扑排序相关推荐

  1. 图论--拓扑排序--判断一个图能否被拓扑排序

    拓扑排序的实现条件,以及结合应用场景,我们都能得到拓扑排序适用于DAG图(Directed Acyclic Graph简称DAG)有向无环图, 根据关系我们能得到一个线性序列,实现的方式是DFS,具体 ...

  2. java 有向无环图 树_拓扑排序-有向无环图(DAG, Directed Acyclic Graph)

    条件: 1.每个顶点出现且只出现一次. 2.若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面. 有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说. 一 ...

  3. 有向无环图的所有拓扑排序

    有向无环图的所有拓扑排序 对有向无环图DAG的拓扑排序是顶点的线性排序,从而使每一有向边[u,v][u,v][u,v],顶点u进来的顺序v在.如果图不是 DAG,则无法对图进行拓扑排序. 给定一个 D ...

  4. 图综合练习--拓扑排序_03 数据结构与算法 - 排序

    1. 冒泡排序 Bubble Sort 基本思想 给定一个数组,这些元素将通过相互之间的比较,按照大小顺序一个个地像气泡一样浮出水面 实现 每一轮,从头部开始,每两个元素比较大小进行交换,直到这一轮中 ...

  5. 【数据结构-图】4.拓扑排序和关键路径(注解+原理)

    一.拓扑排序 1.1 基本知识 有向无环图:一个有向图中不存在环,简称DAG图 AOV网:用DAG图表示一个工程,其顶点表示活动,用有向边 <Vi,Vj><V_i, V_j>& ...

  6. 图综合练习--拓扑排序_拓扑排序

    一个场景 在大学里,每当到了期末的时候,你一定会头疼于选课给你带来的困扰.其中一项就是先修课的问题,每次你高高兴兴地选了自己心仪的选修课时,却发现自己不满足先修课的要求,只好默默地退掉.到底怎样安排我 ...

  7. 有向无环图中的拓扑排序

    ´有向无环图(DAG),指不存在环的有向图 ´点的入度,指以这个点为结束点的边数 ´点的出度,指以这个点为出发点的边数 ´拓扑序就是对于节点的一个排列使得若(u,v)∈E,那么u在排列中出现的位置一定 ...

  8. 数据结构——AOV图与算法——拓扑排序

    AOV图:以有向图中的顶点来表示活动,以有向边来表示活动之间的先后次序关系. 拓扑排序:对一个有向无环图(AOV)进行活动先后的排序方法 拓扑排序思路: 1.统计所有节点的入度 2.把所有入度为0的节 ...

  9. 图的逆拓扑排序(回路识别)

    目录 背景 实现思路 代码 背景 在学习拓扑排序的时候,老师提出了一个问题:在逆拓扑排序算法中如何识别出回路? 总所周知,拓扑排序必须在DAG(有向无环图)中实现,也就是说如果给定的图带有回路,就无法 ...

  10. 图——深度优先遍历(DFS)实现有向无环图的逆拓扑排序

    对图的深度遍历与对树的深度遍历思想类似,采用的是递归函数的办法. 如果是非连通图,则DFS遍历所有顶点即可. //Graph 图 //vertex 顶点,用一个int型变量表示//返回有向图G中顶点v ...

最新文章

  1. linux命令行安装使用KVM
  2. linux哪个命令不可以查看文件内容,linux命令--查看文件内容
  3. hadoop中MapReduce中压缩的使用及4种压缩格式的特征的比较
  4. 海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找
  5. ListBox简单应用
  6. 《Windows 系列》- 右击添加管理员权限
  7. Mysql事务以及加锁机制事务的特征ACID
  8. 最近很火的百度MIP之 zblog改造
  9. 客座编辑:李建平(1976-),男,博士,中国科学院科技战略研究院系统分析与管理所研究员、所长...
  10. 推荐Python十大经典练手项目,让你的Python技能点全亮!
  11. 就地升级Lync Server 到Skype for Business Server
  12. spm_预处理实验记录
  13. 计算机专业毕业论文题目大全集
  14. mysql数据库双机备份_MySQL数据库双机热备份
  15. GitDown: 下载Github特定文件夹
  16. ERR Target instance replied with error: NOAUTH Authentication required
  17. 莫队算法 (普通莫队、带修莫队、树上莫队)
  18. 五分频电路(50%占空比)
  19. Matlab学习日记(5)二维曲线的绘制(plot与fplot)
  20. python实现一个简单的计时器

热门文章

  1. system函数阻塞问题
  2. java方法(超详细!)
  3. java视频直播_java视频直播、聊天室、弹幕、多端适配
  4. 告诉你4个实用方法!美女失业挣了10W,想靠自媒体翻身吗?
  5. 17. Nginx + keepalived 高可用
  6. 三种引流方法案例分析
  7. css給一个角加圆角,css圆角边框不起作用怎么办
  8. 微信开发之ngrok 302错误
  9. 什么是算法?试从日常生活中找3个例子,描述它们的算法
  10. html弹性布局两盒,CSS中的弹性盒子总结