注:有向无环图(DAG图)
AOV网:用顶点表示活动,用弧表示活动之间的优先关系的有向图称为顶点表示活动的网
注:AOV网一定是有向无环图
拓扑序列:对于一个有n个顶点的有向图,顶点序列v1,v2...vn若满足从顶点vi到vj有一条路径,则顶点序列中vi必在vj之前,这样的一个顶点序列为一个拓扑序列
拓扑排序:对一个有向无环图构造拓扑排序的过程(同时还可以判断图内部是否成环)
1.在有向图中选一个没有前驱的顶点并输出
2.从图中删除该顶点和所有以他为尾的弧
重复上述两步,直至全部顶点均已输出,或者当前图不存在无前驱的顶点为止,后一种情况说明有向图中存在环
应用:拓扑序列,关键路径
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//引入一个栈,用于保存所有入度为零的的点的下标
class Stack_Node
{
public:
int data;
Stack_Node* next;
};
class m_Stack
{
public:
Stack_Node* head;
public:
m_Stack()
{
head = new Stack_Node;
if (head == nullptr)
{
cout << "开辟失败" << endl;
}
else
{
head->next = nullptr;
}
}
void m_push(int k)
{
Stack_Node* s = new Stack_Node;
s->data = k;
s->next = head->next;
head->next = s;
}
int m_pop()
{
if (head->next == nullptr)
{
cout << "栈空" << endl;
return -1;
}
else
{
int ret(0);
Stack_Node* p = head->next;
head->next = p->next;
ret = p->data;
delete p;
p = nullptr;
return ret;
}
}
};
//邻接表存有向图
class List_Node
{
public:
int data;//邻接点下标
List_Node* next;
};
class Graph_Node
{
public:
char data;//顶点编号
List_Node* first;//出边链表头指针
};
class Graph
{
public:
int size1;//点的个数
int size2;//边的个数
Graph_Node* g;//邻接表
int* ind;//入度数组
char* topo;//拓扑序列
public:
Graph(int sz1,int sz2):size1(sz1),size2(sz2)
{
g = new Graph_Node[sz1];
ind = new int[sz1];
topo = new char[sz1];
if (g == nullptr || ind == nullptr || topo == nullptr)
{
cout << "开辟失败" << endl;
}
else
{
//初始化点
for (int i = 0; i < sz1; ++i)
{
cin >> g[i].data;
g[i].first = nullptr;
ind[i] = 0;
topo[i] = 0;
}
//输入边
char x(0);
char y(0);
int xi(0);
int yi(0);
for (int i = 0; i < sz2; ++i)
{
cin >> x >> y;
//找x,y对应下标
xi = find(x);
yi = find(y);
//y为x邻接点
List_Node* s = new List_Node;
s->data = yi;
//进行头插
s->next = g[xi].first;
g[xi].first = s;
//统计y入度
ind[yi]++;
}
}
}
int find(char k)
{
for (int i = 0; i < size1; ++i)
{
if (g[i].data == k)
{
return i;
}
}
return -1;
}
bool topo_sort()
{
bool flag = false;//判断能否找到拓扑序列
//引入一个栈,用于保存所有入度为零的的点的下标
m_Stack s;
for (int i = 0; i < size1; ++i)
{
if (ind[i] == 0)
{
s.m_push(i);
}
}
int v_i(0);//出栈点的下标
//j为topo数组下标
for (int i = 0,j = 0; i < size1; ++i,++j)
{
v_i = s.m_pop();
if (v_i == -1)
{
flag = false;//找不到拓扑序列
break;
}
//删除(并没有真正删除,只是入度减一)
topo[j] = g[v_i].data;
List_Node* p = g[v_i].first;
int a(0);//存储入度数组下标
while (p != nullptr)
{
a = p->data;
ind[a]--;
if (ind[a] == 0)
{
s.m_push(a);
}
p = p->next;
}
if (i == size1 - 1)
{
flag = true;
}
}
if (flag == false)
{
cout << "该图带环,无拓扑序列" << endl;
return flag;
}
else
{
cout << "该图拓扑序列为:" << endl;
for (int i = 0; i < size1; ++i)
{
cout << topo[i] << ' ';
}
return flag;
}
}
};
int main()
{
Graph g(6, 8);
g.topo_sort();
return 0;
}
/*
6 8
A B C D E F
A B
A C
A D
C B
C E
F D
F E
D E
*/