(1)如何判断一个图是不是含有环?
a. DFS,出现返回边则有环。
b. 拓扑排序,若所有的顶点都出现在拓扑排序中,则不出现环。
(2)拓扑排序
a.什么是偏序,全序?from:
http://www.programfan.com/club/showbbs.asp?id=221968
偏序是由实数中的
>=
和
<=
抽象出来的
在一个集合F中定义一个比较关系, 这个关系不要求任意两个元素都能比较
这个关系可以任意定义,记为 < , 但是定义的关系要满足以下3个条件
1 ) 任意a属于F,有a < a; ...说明元素自己可以和自己比较
2 ) 如果a和b能比较 且a < b, b和c能比较,且 b < c
那么a和c就能比较,且a < c ...说明比较关系具有传递性
3 ) 如果a和b能比较,且a < b, b < a, 那么a = b
定义的这种满足以上3条公理的比较关系就叫偏序,和所在的集合记为( F, < )
全序首先是偏序,但是比偏序多一个要求:集合中的任意两个元素都是可比的。
在一个集合F中定义一个比较关系, 这个关系不要求任意两个元素都能比较
这个关系可以任意定义,记为 < , 但是定义的关系要满足以下3个条件
1 ) 任意a属于F,有a < a; ...说明元素自己可以和自己比较
2 ) 如果a和b能比较 且a < b, b和c能比较,且 b < c
那么a和c就能比较,且a < c ...说明比较关系具有传递性
3 ) 如果a和b能比较,且a < b, b < a, 那么a = b
定义的这种满足以上3条公理的比较关系就叫偏序,和所在的集合记为( F, < )
全序首先是偏序,但是比偏序多一个要求:集合中的任意两个元素都是可比的。
b.拓扑排序:
由偏序定义得到拓扑有序的操作便是拓扑排序(topological order)。
算法:
(1) 在有向图中选一个没有前驱的顶点输出。
(2) 从图中删除该定点和所有以它为尾的弧。
(3) 重复前两步,直至所有节点都输出,或当前图中不存在无前驱的节点(存在环)。
图采用邻接表实现,头文件代码如下:
#define
MAX_VERTEX_NUM 20
typedef int InfoType;
typedef char VertexType;
typedef enum ... {DG, DN, UDG, UDN} GraphKind;
typedef struct ArcNode ... {
int adjvex;
struct ArcNode *next;
InfoType info;
} ArcNode;
typedef struct VNode ... {
int in_degree;
VertexType data;
ArcNode *firstarc;
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct ... {
AdjList vertex;
int vexnum, arcnum;
GraphKind kind;
} algraph;
typedef int InfoType;
typedef char VertexType;
typedef enum ... {DG, DN, UDG, UDN} GraphKind;
typedef struct ArcNode ... {
int adjvex;
struct ArcNode *next;
InfoType info;
} ArcNode;
typedef struct VNode ... {
int in_degree;
VertexType data;
ArcNode *firstarc;
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct ... {
AdjList vertex;
int vexnum, arcnum;
GraphKind kind;
} algraph;
源文件代码:
#include
"
algraph_topo.h
"
#include " stdio.h "
#include " stdlib.h "
void createDN(algraph & g) ... {}
void createUDN(algraph & g) ... {}
void createUDG(algraph & g) ... {}
// locate the name vertice's index
int locate(algraph g, char name) ... {
for(int i = 0; i < g.vexnum; i++)...{
if(name == g.vertex[i].data)...{
return i;
}
}
return -1;
}
void createDG(algraph & g) ... {
printf("input the number of vertex and arcs: ");
scanf("%d %d", &g.vexnum, &g.arcnum);
fflush(stdin);
int i = 0, j = 0, k = 0;
printf("input the name of vertex: ");
for(i = 0; i < g.vexnum; i++)...{
scanf("%c", &g.vertex[i].data);
fflush(stdin);
g.vertex[i].firstarc = NULL;
g.vertex[i].in_degree = 0;
}
//construct the adjacent list
char v1, v2;
int w;
ArcNode *p;
printf("input the %d arcs v1 v2 and weight: ", g.arcnum);
for(k = 0; k < g.arcnum; k++)...{
scanf("%c %c %d", &v1, &v2, &w);
fflush(stdin);
i = locate(g, v1);
j = locate(g, v2);
//new a node
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->info = w;
p->next = NULL;
//insert the node in the head of list
if(!g.vertex[i].firstarc)...{
g.vertex[i].firstarc = p;
}else...{
p->next = g.vertex[i].firstarc;
g.vertex[i].firstarc = p;
}
g.vertex[j].in_degree++;
}
}
// print the list
void printGraph(algraph g) ... {
for(int i = 0; i < g.vexnum; i++)...{
printf("%c's adjacent list is: ", g.vertex[i].data);
ArcNode *p = g.vertex[i].firstarc;
while(p)...{
printf("%c(%d) ", g.vertex[p->adjvex].data, p->info);
p = p->next;
}
printf(" ");
}
}
void createGragh(algraph & g) ... {
printf("please input the type of graph: ");
scanf("%d", &g.kind);
switch(g.kind)...{
case DG:
createDG(g);
//printGraph(g);
break;
case DN:
createDN(g);
break;
case UDG:
createUDG(g);
break;
case UDN:
createUDN(g);
break;
}
}
// ²éÕÒÏÂÒ»¸ö
int findNext(algraph g) ... {
for(int i = 0; i < g.vexnum; i++)...{
if(g.vertex[i].in_degree == 0)...{
return i;
}
}
return -1;
}
// topo order
void topoSort(algraph g) ... {
printf("the topo sort of graph is: ");
for(int i = 0; i < g.vexnum; i++)...{
int index = findNext(g);
if(index > -1)...{
printf("%c ", g.vertex[index].data);
//don't consider the vertice again
g.vertex[index].in_degree = -1;
ArcNode *p = g.vertex[index].firstarc;
while(p)...{
g.vertex[p->adjvex].in_degree--;
p = p->next;
}
}else...{
break;
}
}
printf(" ");
}
void main() ... {
algraph g;
createGragh(g);
topoSort(g);
}
#include " stdio.h "
#include " stdlib.h "
void createDN(algraph & g) ... {}
void createUDN(algraph & g) ... {}
void createUDG(algraph & g) ... {}
// locate the name vertice's index
int locate(algraph g, char name) ... {
for(int i = 0; i < g.vexnum; i++)...{
if(name == g.vertex[i].data)...{
return i;
}
}
return -1;
}
void createDG(algraph & g) ... {
printf("input the number of vertex and arcs: ");
scanf("%d %d", &g.vexnum, &g.arcnum);
fflush(stdin);
int i = 0, j = 0, k = 0;
printf("input the name of vertex: ");
for(i = 0; i < g.vexnum; i++)...{
scanf("%c", &g.vertex[i].data);
fflush(stdin);
g.vertex[i].firstarc = NULL;
g.vertex[i].in_degree = 0;
}
//construct the adjacent list
char v1, v2;
int w;
ArcNode *p;
printf("input the %d arcs v1 v2 and weight: ", g.arcnum);
for(k = 0; k < g.arcnum; k++)...{
scanf("%c %c %d", &v1, &v2, &w);
fflush(stdin);
i = locate(g, v1);
j = locate(g, v2);
//new a node
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->info = w;
p->next = NULL;
//insert the node in the head of list
if(!g.vertex[i].firstarc)...{
g.vertex[i].firstarc = p;
}else...{
p->next = g.vertex[i].firstarc;
g.vertex[i].firstarc = p;
}
g.vertex[j].in_degree++;
}
}
// print the list
void printGraph(algraph g) ... {
for(int i = 0; i < g.vexnum; i++)...{
printf("%c's adjacent list is: ", g.vertex[i].data);
ArcNode *p = g.vertex[i].firstarc;
while(p)...{
printf("%c(%d) ", g.vertex[p->adjvex].data, p->info);
p = p->next;
}
printf(" ");
}
}
void createGragh(algraph & g) ... {
printf("please input the type of graph: ");
scanf("%d", &g.kind);
switch(g.kind)...{
case DG:
createDG(g);
//printGraph(g);
break;
case DN:
createDN(g);
break;
case UDG:
createUDG(g);
break;
case UDN:
createUDN(g);
break;
}
}
// ²éÕÒÏÂÒ»¸ö
int findNext(algraph g) ... {
for(int i = 0; i < g.vexnum; i++)...{
if(g.vertex[i].in_degree == 0)...{
return i;
}
}
return -1;
}
// topo order
void topoSort(algraph g) ... {
printf("the topo sort of graph is: ");
for(int i = 0; i < g.vexnum; i++)...{
int index = findNext(g);
if(index > -1)...{
printf("%c ", g.vertex[index].data);
//don't consider the vertice again
g.vertex[index].in_degree = -1;
ArcNode *p = g.vertex[index].firstarc;
while(p)...{
g.vertex[p->adjvex].in_degree--;
p = p->next;
}
}else...{
break;
}
}
printf(" ");
}
void main() ... {
algraph g;
createGragh(g);
topoSort(g);
}
程序的运行结果如下:
please input the type of graph:
0
input the number of vertex and arcs:
6 8
input the name of vertex:
a
b
c
d
e
f
input the 8 arcs v1 v2 and weight:
a d 1
a c 1
a b 1
c e 1
c b 1
d e 1
f e 1
f d 1
the topo sort of graph is :
a c b f d e
Press any key to continue
0
input the number of vertex and arcs:
6 8
input the name of vertex:
a
b
c
d
e
f
input the 8 arcs v1 v2 and weight:
a d 1
a c 1
a b 1
c e 1
c b 1
d e 1
f e 1
f d 1
the topo sort of graph is :
a c b f d e
Press any key to continue
说明:
(1) 为了避免重复检测入度为0的顶点,可设置一个栈暂存所有入度为0的顶点,复杂度为O(n + e)。而在程序中采用的是
//
don't consider the vertice again
g.vertex[index].in_degree = - 1 ;
g.vertex[index].in_degree = - 1 ;
来实现的。复杂度要高一些。
(2) 可以使用DFS,退出DFS函数的顺序即为逆向的拓扑有序序列。
(3)关键路径
a. AOV网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网(activity on vertex network)。AOV网中,没有有向环。
b. AOE网:边表示活动的网络(顶点表示事件,弧表示活动),用来估算工程的完成时间,通常只有一个源点和一个汇点。
c. 求AOE算法的复杂度是O(n + e)