AOV(Activity On Vertex network)网,用有向图表示活动之间的制约关系,顶点表达活动,弧表示活动之间的优先制约关系,这种有向图为顶点表示活动的网,简称AOV网。
AOE(Activity On Edge)网,弧表示活动,以顶点表示活动的开始或结束时间,这种有向图为边表示活动的网,称为AOE网
1、算法步骤
重点:一个AOV网的拓扑序列不是唯一的
2、代码实现
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
const int MaxVnum = 100; //顶点数最大值
int indegree[MaxVnum]; //入度数组
typedef string VexType; //顶点的数据类型为字符型
typedef struct AdjNode
{ //定义邻接点类型
int v; //邻接点下标
struct AdjNode *next; //指向下一个邻接点
} AdjNode;
typedef struct VexNode
{ //定义顶点类型
; // VexType为顶点的数据类型,根据需要定义
VexType data*first; //指向第一个邻接点
AdjNode } VexNode;
typedef struct
{ //包含邻接表和逆邻接表
[MaxVnum]; //定义邻接表
VexNode Vex[MaxVnum]; //定义逆邻接表
VexNode converse_Vexint vexnum, edgenum; //顶点数,边数
} ALGragh;
int locatevex(ALGragh G, VexType x)
{
for (int i = 0; i < G.vexnum; i++) //查找顶点信息的下标
if (x == G.Vex[i].data)
return i;
return -1; //没找到
}
void insertedge(ALGragh &G, int i, int j) //插入一条边
{
*s1, *s2;
AdjNode = new AdjNode; //创建邻接表结点
s1 ->v = j;
s1->next = G.Vex[i].first;
s1.Vex[i].first = s1;
G= new AdjNode; //创建逆邻接表结点
s2 ->v = i;
s2->next = G.converse_Vex[j].first;
s2.converse_Vex[j].first = s2;
G}
void printg(ALGragh G) //输出邻接表
{
<< "----------邻接表如下:----------" << endl;
cout for (int i = 0; i < G.vexnum; i++)
{
*t = G.Vex[i].first;
AdjNode << G.Vex[i].data << ": ";
cout while (t != NULL)
{
<< "[" << t->v << "] ";
cout = t->next;
t }
<< endl;
cout }
<< "----------逆邻接表如下:----------" << endl;
cout for (int i = 0; i < G.vexnum; i++)
{
*t = G.converse_Vex[i].first;
AdjNode << G.converse_Vex[i].data << ": ";
cout while (t != NULL)
{
<< "[" << t->v << "] ";
cout = t->next;
t }
<< endl;
cout }
}
void CreateALGraph(ALGragh &G) //创建有向图的邻接表和逆邻接表
{
int i, j;
, v;
VexType u<< "请输入顶点数和边数:" << endl;
cout >> G.vexnum >> G.edgenum;
cin << "请输入顶点信息:" << endl;
cout for (i = 0; i < G.vexnum; i++) //输入顶点信息,存入顶点信息数组
{
>> G.Vex[i].data;
cin .converse_Vex[i].data = G.Vex[i].data;
G.Vex[i].first = NULL;
G.converse_Vex[i].first = NULL;
G}
<< "请依次输入每条边的两个顶点u,v" << endl;
cout while (G.edgenum--)
{
>> u >> v;
cin = locatevex(G, u); //查找顶点u的存储下标
i = locatevex(G, v); //查找顶点v的存储下标
j if (i != -1 && j != -1)
(G, i, j);
insertedgeelse
{
<< "输入顶点信息错!请重新输入!" << endl;
cout .edgenum++; //本次输入不算
G}
}
}
//O(e)
void FindInDegree(ALGragh G) //求出各顶点的入度存入数组indegree中
{
int i, count;
for (i = 0; i < G.vexnum; i++)
{
= 0;
count *p = G.converse_Vex[i].first;
AdjNode if (p)
{
while (p)
{
= p->next;
p ++;
count}
}
[i] = count;
indegree}
<< "入度数组为:" << endl;
cout for (int i = 0; i < G.vexnum; i++) //输出入度数组
<< indegree[i] << "\t";
cout << endl;
cout }
bool TopologicalSort(ALGragh G, int topo[]) //拓扑排序
{
//有向图G采用邻接表存储结构
//若G无回路,则生成G的一个拓扑序列topo[]并返回true,否则false
int i, m;
<int> S; //初始化一个栈S,需要引入头文件#include<stack>
stack(G); //求出各顶点的入度存入数组indegree[]中O(e)
FindInDegree//O(n)
for (i = 0; i < G.vexnum; i++)
if (!indegree[i]) //入度为0者进栈
.push(i);
S= 0; //对输出顶点计数,初始为0
m //O(e)
while (!S.empty()) //栈S非空
{
= S.top(); //取栈顶顶点i
i .pop(); //栈顶顶点i出栈
S[m] = i; //将i保存在拓扑序列数组topo中
topo++; //对输出顶点计数
m*p = G.Vex[i].first; // p指向i的第一个邻接点
AdjNode while (p) // i的所有邻接点入度减1
{
int k = p->v; // k为i的邻接点
--indegree[k]; // i的每个邻接点的入度减1
if (indegree[k] == 0) //若入度减为0,则入栈
.push(k);
S= p->next; // p指向顶点i下一个邻接结点
p }
}
if (m < G.vexnum) //该有向图有回路
return false;
else
return true;
}
int main()
{
;
ALGragh Gint *topo = new int[G.vexnum];
(G); //创建有向图的邻接表和逆邻接表
CreateALGraph(G); //输出邻接表和逆邻接表
printgif (TopologicalSort(G, topo))
{
<< "拓扑序列为:" << endl;
cout for (int i = 0; i < G.vexnum; i++) //输出拓扑序列
<< topo[i] << "\t";
cout }
else
<< "该图有环,无拓扑序列!" << endl;
cout return 0;
}
3、复杂度分析
求有向图各顶点的入度需要遍历邻接表,O(e)。开始选择出入度为0的顶点入栈O(n),每个顶点出栈后其邻接点入度减1,O(e)。总时间复杂度为O(n+e)。
入度数组indegree[],topo[],statck s,空间复杂度为O(n)。
4、重要应用
拓扑排序是检测AOV网中是否存在环的方法。进行拓扑排序后所有顶点都在序列中,则不存在环。