DAG和概念
有向无环图:顾名思义,有向图,且不含环,directed acycline graph,简称DAG图。
无向图检查环:若深度优先遍历过程遇到回边(先前访问过的顶点的边),则必定存在环。
有向图检查环:从某个顶点v出发,在dfs(v)结束前,出现一条从顶点u到顶点v的回边,由于u在生成树上是v的子孙,则有向图必定存在包含顶点v和u之间的环。
DAG图是描述工程的有效工具。一个工程可以用一个DAG图表示,每一个顶点是一个子工程,工程的先后关系用弧表示。
围绕着工程,两个关心的问题是:
1、工程能否顺利进行(拓扑排序问题)
2、工程完成所必须的最短时间(关键路径问题)
AOV网和拓扑排序
偏序:集合中仅有部分成员之间可以比较。
全序:集合中全体成员均可比较。
比如下图左边是偏序,右边是全序。
拓扑有序:全序上面的排序
拓扑排序:由于集合上一个偏序得到该集合上的一个全序。
AOV网(Activity On Vertex Network):用顶点表示活动,用弧表示活动之间的优先关系的有向图称为顶点表示活动的网。
在AOV网上不应该出现有向环,因此,给定一个AOV网,要先判断是否存在环。
AOV图求拓扑排序的算法如下:
1、从有向图中选取一个没有前驱的顶点(入度为0的)。
2、从图中删除该顶点和所有以它为尾的弧(此时可能会产生新的无前驱顶点)。
循环上述两步,直到
(1)所有顶点都全部输出。
Or
(2)不存在无前驱的顶点,说明图中有环。
上述算法非常简单明了,连AOV图的环判定也一起做了。
具体到实现,我们可以增添两个数据结构:
(1) 存放各个顶点入度的集合indegree。
(2)一个暂存入度为0的栈。
算法变成了:
1、扫描所有顶点的入度。
2、将入度为0的,入栈。
3、循环直到栈空
弹出栈、输出。
将关联的边入度减1,如果为0,入栈。
4、最终检查输出了多少个结点,如果小于nvexs,说明有环。
代码如下:
注意这里是有向图,图的创建不能在用无向图的双边了!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_VEXS 100
#define MAX_QUEUE 1000
// Arc
struct Arc
{
int ivex; // The vex position in vexs array
struct Arc* next;
};
// Vex
struct Vex
{
int data;
struct Arc* first_arc;
};
// Graph
struct Graph
{
struct Vex vexs[MAX_VEXS];
int nvexs;
int narcs;
};
int graph_locate(struct Graph* g, int val)
{
int i;
for(i=0; i<g->nvexs; i++)
{
if(g->vexs[i].data==val)
{
return i;
}
}
return -1;
}
void graph_add_arc(struct Graph* g, int x, int y)
{
// New arc
struct Arc* new_arc = (struct Arc*)malloc(sizeof(struct Arc));
struct Arc* ptr = NULL;
if(!new_arc)
{
return ;
}
new_arc->ivex = y;
new_arc->next = NULL;
// Find vexs[x]'s tail
if(!g->vexs[x].first_arc)
{
g->vexs[x].first_arc = new_arc;
}else
{
ptr = g->vexs[x].first_arc;
while(ptr->next!=NULL)
{
ptr = ptr->next;
}
ptr->next = new_arc;
}
}
void graph_create(struct Graph* g)
{
int i;
int x, y;
struct Arc* ptr;
// Get n vexs
printf("Please enter n for number of vexs:\n");
scanf("%d", &g->nvexs);
for(i=0; i<g->nvexs; i++)
{
printf("Please enter a int for vexs(%d):\n", i);
scanf("%d", &g->vexs[i].data);
g->vexs[i].first_arc = NULL;
}
// Get m arcs;
printf("Please enter m for number of vexs:\n");
scanf("%d", &g->narcs);
for(i=0; i<g->narcs; i++)
{
printf("Please enter x y for arcs(%d):\n", i);
scanf("%d %d", &x, &y);
x = graph_locate(g, x);
y = graph_locate(g, y);
if(x==-1 || y==-1)
{
printf("Wrong x or y for arcs(%d).\n", i);
i--;
}
// arc x->y
graph_add_arc(g, x, y);
}
}
void graph_print(struct Graph* g)
{
int i;
struct Arc* ptr;
// Just print arcs
for(i=0;i<g->nvexs;i++)
{
ptr = g->vexs[i].first_arc;
while(ptr)
{
printf("%d->%d\n", g->vexs[i].data, g->vexs[ptr->ivex].data);
ptr = ptr->next;
}
}
}
void graph_init(struct Graph* g)
{
int i;
for(i=0; i<MAX_VEXS; i++)
{
g->vexs[i].first_arc = NULL;
}
g->nvexs = 0;
g->narcs = 0;
}
void graph_free(struct Graph* g)
{
int i;
struct Arc* ptr;
struct Arc* free_node;
g->nvexs = 0;
g->narcs = 0;
for(i=0; i<MAX_VEXS; i++)
{
ptr = g->vexs[i].first_arc;
while(ptr!=NULL)
{
free_node = ptr;
ptr = ptr->next;
free(free_node);
}
}
}
#define MAX_STACK 100
struct Stack
{
int top;
int data[MAX_STACK];
};
void stack_init(struct Stack* stk)
{
stk->top = 0;
}
int stack_push(struct Stack* stk, int v)
{
if(stk->top>=MAX_STACK)
{
return -1;
}else
{
stk->data[stk->top++] = v;
return 0;
}
}
int stack_pop(struct Stack* stk, int* v)
{
if(stk->top==0)
{
return -1;
}else
{
*v = stk->data[--stk->top];
return 0;
}
}
int stack_is_empty(struct Stack* stk)
{
return stk->top==0;
}
void topo_sort(struct Graph* g)
{
// Count indegree for all vex
int* indeg = (int*)malloc(sizeof(int)*g->nvexs);
int i;
int cnt = 0;
struct Arc* ptr = NULL;
for(i=0;i<g->nvexs;i++)
{
indeg[i] = 0;
}
for(i=0;i<g->nvexs;i++)
{
ptr = g->vexs[i].first_arc;
while(ptr!=NULL)
{
indeg[ptr->ivex]++;
ptr = ptr->next;
}
}
// Stack push all 0-indegree
struct Stack* stk = (struct Stack*)(malloc(sizeof(struct Stack)));
stack_init(stk);
for(i=0;i<g->nvexs;i++)
{
if(indeg[i]==0)
{
if(-1==stack_push(stk, i))
{
printf("Push fail...\n");
break;
}
}
}
// While !stack.empty()
while(!stack_is_empty(stk))
{
int tmp;
if(-1==stack_pop(stk, &tmp))
{
printf("Pop fail...\n");
break;
}else
{
// Output an vex
printf("%d\n", g->vexs[tmp].data);
cnt++;
// Count-- for every vex[tmp]'s neigbhour
ptr = g->vexs[tmp].first_arc;
while(ptr!=NULL)
{
if(--indeg[ptr->ivex]==0)
{
stack_push(stk, ptr->ivex);
}
ptr = ptr->next;
}
}
}
// Free malloc resource
free(stk);
free(indeg);
if(cnt<g->nvexs)
{
printf("This graph has cycle!!!\n");
}
}
int main()
{
struct Graph g;
graph_init(&g);
graph_create(&g);
topo_sort(&g);
graph_free(&g);
return 0;
}
测试的AVO图:
测试数据:
6 1 2 3 4 5 6 8 1 2 1 3 1 4 3 2 3 5 4 5 6 4 6 5
测试输出:
6 1 4 3 5 2

