问题:有向无环图的拓扑排序
拓扑排序:由某个集合上的一个偏序关系得到该集合上的一个全序关系。
算法用了一个全局数组InDegreee来记录集合中顶点的入度,用栈来保存入度为0的元素。首先让所有入度为0的顶点进栈,然后让栈中的元素出栈,出栈过程中,与该顶点相连的顶点的入度相应减1,若入度变为0了,则相应入栈。
结束状态:所有元素的入度都为0,栈为空,所有顶点元素都已经完成拓扑排序;否则,存在环路。
#include<iostream>
using namespace std;
#define MAX 100 //顶点的最大个数
int InDegree[MAX+1]; //记录顶点入度的数组
typedef char SElemType; //定义栈的数据类型
typedef int Status; //定义栈操作的返回值类型
#define ERROR 0 //栈操作失败的返回值
#define OK 1 //栈操作成功的返回值
#define MAXNAME 5 //活动名字的最长值
#define INFINIT INT_MAX //定义最大整数
typedef struct stack
{
SElemType *base;
SElemType *top;
int stacksize;
}stack; //栈定义
Status Init(stack &s) //栈的初始化
{
s.base=new char[MAX];
if(s.base==NULL)
{
cout<<"栈内存空间申请不成功~"<<endl;
return ERROR;
}
s.top=s.base;
s.stacksize=0;
return OK;
}
Status Push(stack &s,char ch)
{
if(s.stacksize==MAX)
{
cout<<"栈内存向上溢出~"<<endl;
return ERROR;
}
*s.top++=ch;
s.stacksize++;
return OK;
}
Status Pop(stack &s,char &ch)
{
if(0==s.stacksize)
{
cout<<"栈内存向下溢出~"<<endl;
return ERROR;
}
s.top--;
ch=*(s.top);
s.stacksize--;
return OK;
}
int Empty(stack s)
{
if(s.base==s.top)
return 1;
else
return 0;
}
typedef struct ArcNode
{
int adjvex;
int weight;
int a; //该弧对应的活动的序号
struct ArcNode* nextarc;
}ArcNode; //表结点的定义
typedef struct HNode
{
char info;
ArcNode *firstarc;
}HNode,AdjList[MAX+1]; //头结点和顶点数组的定义,其中,顶点数组的0号单元不存储
typedef struct ALGraph
{
AdjList vertex;
int vexnum;
int arcnum;
}ALGraph; //邻接表的定义
int LocateVex(ALGraph G,char ch) //定位顶点在邻接表中的位置
{
for(int i=1;i<=G.vexnum;i++)
{
if(ch==G.vertex[i].info)
return i;
}
return 0;
}
void CreateALGraph(ALGraph &G) //创建邻接表
{
char ch1,ch2;
int w;
int pos1,pos2;
int s;
ArcNode *p,*q;
cout<<"请输入顶点个数和边数:";
cin>>G.vexnum>>G.arcnum;
cout<<"请依次输入"<<G.vexnum<<"个顶点的信息:";
for(int i=1;i<=G.vexnum;i++)
{
cin>>G.vertex[i].info;
G.vertex[i].firstarc=NULL;
}
cout<<"请依次输入每条弧的弧尾 弧头 权值以及该弧对应的活动序号:"<<endl;
cout<<'H'<<' '<<'T'<<' '<<'W'<<' '<<'N'<<endl;
for(i=1;i<=G.arcnum;i++)
{
cin>>ch1>>ch2>>w>>s;
pos1=LocateVex(G,ch1);
pos2=LocateVex(G,ch2);
q=new ArcNode;
q->adjvex=pos2;
q->nextarc=NULL;
q->weight=w;
q->a=s;
p=G.vertex[pos1].firstarc;
if(p==NULL)
G.vertex[pos1].firstarc=q;
else
{
while(p->nextarc!=NULL)
{
p=p->nextarc;
}
p->nextarc=q;
}
InDegree[pos2]++;
}
}
Status PoloSort(ALGraph G,int ee[],int el[])
{
stack s,t;
Init(s);
Init(t);
char ch;
int pos1,pos2;
int num=0;
ArcNode *p;
for(int i=1;i<G.vexnum;i++)
{
ee[i]=0;
}
for(i=1;i<G.vexnum;i++)
{
el[i]=INFINIT;
}
for(i=1;i<=G.vexnum;i++)
{
if(0==InDegree[i])
{
Push(s,G.vertex[i].info);
}
}
cout<<"拓扑排序为:";
while(!Empty(s))
{
Pop(s,ch);
cout<<ch<<' ';
Push(t,ch);
num++;
pos1=LocateVex(G,ch);
p=G.vertex[pos1].firstarc;
while(p!=NULL)
{
pos2=p->adjvex;
if(ee[pos1]+p->weight>ee[pos2])
ee[pos2]=ee[pos1]+p->weight;
InDegree[pos2]--;
if(0==InDegree[pos2])
Push(s,G.vertex[pos2].info);
p=p->nextarc;
}
}
cout<<endl;
if(num==G.vexnum)
{
cout<<"顶点序列中所有元素都已经完成排序,拓扑排序成功~"<<endl;
}
else
{
cout<<"顶点序列中存在环路,不能实现拓扑排序~"<<endl;
return ERROR;
}
Pop(t,ch);
pos1=LocateVex(G,ch);
el[pos1]=ee[pos1]; //最后一个事件的最早发生时间和最迟发生时间相同
while(!Empty(t))
{
Pop(t,ch);
pos1=LocateVex(G,ch);
p=G.vertex[pos1].firstarc;
while(p!=NULL)
{
pos2=p->adjvex;
if(el[pos2]-p->weight<el[pos1])
el[pos1]=el[pos2]-p->weight;
p=p->nextarc;
}
}
return OK;
}
void CriticalPath(ALGraph G,int ee[],int el[])
{
int i;
int *e=new int[G.arcnum+1]; //活动的最早发生时间
int *l=new int[G.arcnum+1]; //活动的最迟发生时间
ArcNode *p;
int pos1,pos2;
int pos;
char *n=new char[MAXNAME];
for(i=1;i<=G.vexnum;i++)
{
pos1=i;
p=G.vertex[i].firstarc;
while(p!=NULL)
{
pos2=p->adjvex;
pos=p->a;
e[pos]=ee[pos1];
l[pos]=el[pos2]-p->weight;
p=p->nextarc;
}
}
for(i=1;i<=G.arcnum;i++)
{
if(e[i]==l[i])
cout<<"活动"<<i<<"为关键活动"<<endl;
}
}
void main()
{
ALGraph G;
CreateALGraph(G);
int *ee=new int[G.vexnum+1]; //数组ee记录事件的最早发生时间
int *el=new int[G.vexnum+1]; //数组el记录事件的最迟发生时间
PoloSort(G,ee,el);
CriticalPath(G,ee,el);
}
------------------------------------------------------------------------------
运行结果:
请输入顶点个数和边数:9 11
请依次输入9个顶点的信息:a b c d e f g h i
请依次输入每条弧的弧尾 弧头 权值以及该弧对应的活动序号:
H T W N
a b 6 1
a c 4 2
a d 5 3
b e 1 4
c e 1 5
d f 2 6
e g 9 7
e h 7 8
f h 4 9
g i 2 10
h i 4 11
拓扑排序为:a d f c b e h g i
顶点序列中所有元素都已经完成排序,拓扑排序成功~
活动1为关键活动
活动4为关键活动
活动7为关键活动
活动8为关键活动
活动10为关键活动
活动11为关键活动
Press any key to continue
------------------------------------------------------------------------------
To_make_progress,everyday!