AOV(Activity on Vertex network): 活动在顶点上的网
顶点: 表示活动
边: 表示活动的先后顺序
拓扑排序:
有向无环图G,所有顶点排成一个线性序列
应用:
如下图要先要完成1 ,在2,3,->4,5 ->6
代码实现:上图的拓扑排序
有向无环图,邻接表存储
拓扑排序:
/*
@date: 2020-5-31
@author:wby
AOV(Activity on Vertex network): 活动在顶点上的网
顶点:表示活动
边:表示活动的先后顺序
拓扑排序:
有向无环图G,所有顶点排成一个线性序列
步骤:
1:从有向图中选择一个没有前驱(入度为0)的结点u输出
2:删除1中的输出的顶点u,并且删除u点出发的全部边
3:重复上述两步,直到图中不存在入度为0的顶点
*/
#include <iostream>
#include<cstring>
using namespace std ;
#define MaxSize 50 //图最大顶点个数
#define inf 999999999 //无穷大值,在图中表示不连通
typedef int datatype; //可以根据需要改变数据类型,也可以自己封装数据类型
//邻接表
typedef struct ArcNode{
int adjvex; //该边指向的顶点编号,(邻接点编号)
ArcNode *next ; //指向下一条边的指针
}ArcNode ; //弧结点
typedef struct{
int num ; // 顶点编号信息
int inDegreeCount ; //顶点的入度
int outDegreeCount ; //顶点的出度统计
ArcNode *firstArc ; // 指向第一条边的指针
}VNode ; //结点
typedef struct{
int n,e ; // n 图顶点的总数, e 边数
VNode adjList[MaxSize] ; //各节点邻接表(一个节点一条链表,链表中元素为邻接边顶点adjvex,和边上info)
}AGraph;
/* 构造图的初始函数 */
AGraph* InitiaL_Graph(){
AGraph *graph ;
int n ,e ; // n ,这个图的顶点个数,e 变数
int i;
graph = new AGraph ; //开辟一个图存储空间,不然有空指针异常
cout<<"初始化图操作:请输入你要构造的图的 顶点数(n) 和边数(e)"<<endl ;
cout<<"请输入总的顶点数:n \t";
cin>>n;
cout<<"请输入总的变数:e: \t";
cin>>e;
graph->n = n ;
graph->e = e ;
cout<<"请输入各个顶点的邻接边:\tadjvex: 顶点编号 "<<endl ;
int inDegreeCount[n] ; //用一个数组统计所有顶点的入度信息
memset(inDegreeCount,0,sizeof(inDegreeCount)) ; //清0
for(i=1;i<=n;i++)
inDegreeCount[i] =0 ; //初始时,所有结点的入度为0
i =1 ;
while(i<=n){ //从第1个结点到第n个结点
VNode *vnodei ; //当前节点邻接链
ArcNode *arcNodeHead,*temp_arnode; //节点链表,采用尾插法,temp_arcnode ,是临时结点,arcNodeHead是链表头
int outDegreeCount =0; //当前结点出度信息统计,初始0
vnodei = new VNode ; //分配地址,不然有空指针异常
arcNodeHead = new ArcNode;
arcNodeHead->next =NULL; //初始化链表
arcNodeHead->adjvex=i ; //第一个邻接点,指向自己
temp_arnode = arcNodeHead ;
cout<<"第"<<i<<"个结点的邻接链表,格式:邻结点的: 编号 输入-1结束当前顶点链的输入"<<endl ;
while(true){
int node_num ; //邻结点编号
ArcNode *temp; //临时保存一条邻接边的信息
cin>>node_num;
if(node_num==-1){
temp_arnode->next =NULL ;
break ;
}
temp = new ArcNode ;
temp->adjvex = node_num ;
temp_arnode->next = temp ; //将邻接边加入链表中,尾插法
temp_arnode = temp ; //指针后移动
inDegreeCount[node_num]++ ; //入度,当前链表中出现顶点的入度+1
outDegreeCount++ ; //当前链表输入几个顶点,出度就为几
}
temp_arnode->next=NULL ; //链表尾置为空
vnodei->firstArc =arcNodeHead->next ; //应为第一个结点没有保存领接边信息,后移1位
vnodei->num = i ; //标记为i结的邻接边
graph->adjList[i] = *vnodei; //添加到图的邻接表中
graph->adjList[i].outDegreeCount = outDegreeCount ;
i++ ; //下一个结点
}
for(i=1;i<=n;i++) //将所有入度信息,赋值给图中结点
graph->adjList[i].inDegreeCount =inDegreeCount[i] ;
return graph ;
}
void PrintAdj(AGraph *graph)
{
int i,n,num ;
n = graph->n ; //图的边数
for(i=1;i<=n;i++){
ArcNode *p ;
num = graph->adjList[i].num ; //结点i编号
p= graph->adjList[i].firstArc ; //结点i的邻结点链
cout<<num<<" ->";
while(p){
cout<<p->adjvex<<"->" ; //邻结点编号
p=p->next ;
}
cout<<" 结点<<num<<的入度为"<<graph->adjList[i].inDegreeCount<<" 出度:"<<graph->adjList[i].outDegreeCount<<endl ;
}
}
// 拓扑排序
void TopSort(AGraph * graph)
{
int i,u,v;
int n ;
int visit =0;
int Stack[MaxSize] ,top =-1 ; //栈
n = graph->n ; //图的顶点个数
ArcNode * p ;
for(i=1 ;i<= n ;i++){
if(graph->adjList[i].inDegreeCount == 0){ //将所有入度为0的顶点入栈
Stack[++top] = i ;
}
}
while(top!=-1){
u= Stack[top--] ; //顶点出栈
visit++ ;
cout<<u<<"->" ; //访问当前入度v为0的顶点
p=graph->adjList[u].firstArc; //顶点u的邻接链表
while(p!=NULL){
v = p->adjvex ; //顶点u的邻接顶点v
graph->adjList[v].inDegreeCount-=1; //删除顶点u,所有u的所有邻接点v的入度个数-1
if( graph->adjList[v].inDegreeCount ==0) //更新后的入度为0,进栈
Stack[++top] = v ;
p=p->next ;
}
}
cout<<endl ;
if(visit == n)
cout<<"遍历所有结点"<<endl ;
else
cout<<"失败"<<endl ;
}
int main()
{
int i ,n ;
AGraph *graph = InitiaL_Graph() ; //图的初始化
//打印图的邻接表
cout<<"邻接表"<<endl ;
PrintAdj(graph);
cout<<"这个图的拓扑排序如下"<<endl ;
TopSort(graph) ;
return (1) ;
}
/*
input: n =6 e=8
2 3 -1
4 5 -1
5 6 -1
6 -1
6 -1
-1
*/
Reference:
[1]: 2019版<<>数据结构高分笔记>>天勤