图的应用--拓扑排序
文章目录
- 什么是拓扑排序
- 拓扑排序的过程
- 拓扑排序的实现
- 采用邻接矩阵实现
- 运行结果:
- 采用邻接表实现
- 运行结果:
什么是拓扑排序
拓扑排序经常用于完成有依赖关系的任务的排序。
举个例子:
一个软件工程专业的学生必须学习系列的基本课程,其中有些课程是基础课,独立于其他课程,而另一些课程必须先学完先修课程才可以开始后序课程。这个关系可以用有向图表示。
学生必须按照拓扑有序的顺序来安排学习计划,这样才能保证学习任何一门课程时其先修课程已经学过。
拓扑排序的过程
- 在有向图中找一个无前驱的顶点且输出。
- 删除该顶点指向另外顶点的弧。
- 重复以上两步,直至不存在没有前驱的点
- 若输出的顶点数小于有向图中的顶点数,则说明图中存在环。否则输出的序列即为拓扑排序。
拓扑排序的实现
需要一个辅助数组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;
}
运行结果:
从上面可以看出拓扑排序序列不一定相同,只要满足先序在后序前面即可。
返回顶部
图的应用--拓扑排序相关推荐
- 图论--拓扑排序--判断一个图能否被拓扑排序
拓扑排序的实现条件,以及结合应用场景,我们都能得到拓扑排序适用于DAG图(Directed Acyclic Graph简称DAG)有向无环图, 根据关系我们能得到一个线性序列,实现的方式是DFS,具体 ...
- java 有向无环图 树_拓扑排序-有向无环图(DAG, Directed Acyclic Graph)
条件: 1.每个顶点出现且只出现一次. 2.若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面. 有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说. 一 ...
- 有向无环图的所有拓扑排序
有向无环图的所有拓扑排序 对有向无环图DAG的拓扑排序是顶点的线性排序,从而使每一有向边[u,v][u,v][u,v],顶点u进来的顺序v在.如果图不是 DAG,则无法对图进行拓扑排序. 给定一个 D ...
- 图综合练习--拓扑排序_03 数据结构与算法 - 排序
1. 冒泡排序 Bubble Sort 基本思想 给定一个数组,这些元素将通过相互之间的比较,按照大小顺序一个个地像气泡一样浮出水面 实现 每一轮,从头部开始,每两个元素比较大小进行交换,直到这一轮中 ...
- 【数据结构-图】4.拓扑排序和关键路径(注解+原理)
一.拓扑排序 1.1 基本知识 有向无环图:一个有向图中不存在环,简称DAG图 AOV网:用DAG图表示一个工程,其顶点表示活动,用有向边 <Vi,Vj><V_i, V_j>& ...
- 图综合练习--拓扑排序_拓扑排序
一个场景 在大学里,每当到了期末的时候,你一定会头疼于选课给你带来的困扰.其中一项就是先修课的问题,每次你高高兴兴地选了自己心仪的选修课时,却发现自己不满足先修课的要求,只好默默地退掉.到底怎样安排我 ...
- 有向无环图中的拓扑排序
´有向无环图(DAG),指不存在环的有向图 ´点的入度,指以这个点为结束点的边数 ´点的出度,指以这个点为出发点的边数 ´拓扑序就是对于节点的一个排列使得若(u,v)∈E,那么u在排列中出现的位置一定 ...
- 数据结构——AOV图与算法——拓扑排序
AOV图:以有向图中的顶点来表示活动,以有向边来表示活动之间的先后次序关系. 拓扑排序:对一个有向无环图(AOV)进行活动先后的排序方法 拓扑排序思路: 1.统计所有节点的入度 2.把所有入度为0的节 ...
- 图的逆拓扑排序(回路识别)
目录 背景 实现思路 代码 背景 在学习拓扑排序的时候,老师提出了一个问题:在逆拓扑排序算法中如何识别出回路? 总所周知,拓扑排序必须在DAG(有向无环图)中实现,也就是说如果给定的图带有回路,就无法 ...
- 图——深度优先遍历(DFS)实现有向无环图的逆拓扑排序
对图的深度遍历与对树的深度遍历思想类似,采用的是递归函数的办法. 如果是非连通图,则DFS遍历所有顶点即可. //Graph 图 //vertex 顶点,用一个int型变量表示//返回有向图G中顶点v ...
最新文章
- linux命令行安装使用KVM
- linux哪个命令不可以查看文件内容,linux命令--查看文件内容
- hadoop中MapReduce中压缩的使用及4种压缩格式的特征的比较
- 海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找
- ListBox简单应用
- 《Windows 系列》- 右击添加管理员权限
- Mysql事务以及加锁机制事务的特征ACID
- 最近很火的百度MIP之 zblog改造
- 客座编辑:李建平(1976-),男,博士,中国科学院科技战略研究院系统分析与管理所研究员、所长...
- 推荐Python十大经典练手项目,让你的Python技能点全亮!
- 就地升级Lync Server 到Skype for Business Server
- spm_预处理实验记录
- 计算机专业毕业论文题目大全集
- mysql数据库双机备份_MySQL数据库双机热备份
- GitDown: 下载Github特定文件夹
- ERR Target instance replied with error: NOAUTH Authentication required
- 莫队算法 (普通莫队、带修莫队、树上莫队)
- 五分频电路(50%占空比)
- Matlab学习日记(5)二维曲线的绘制(plot与fplot)
- python实现一个简单的计时器