拓扑排序算法,基本思想:
1、从有向图中选取一个没有前驱(入度为0)的顶点,并输出之
2、从有向图中删去此顶点以及所有以它为尾的弧
3、重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止
数据结构PPT图论在第七章:http://download.csdn.net/download/include_heqile/10188767
使用邻接表和一个用来存储入度为0的节点的栈实现
在算法中需要用定量的描述替代定性的概念
没有前驱的顶点 <==> 入度为零的顶点
删除顶点及以它为尾的弧 <==> 弧头顶点的入度减1
为实现拓扑排序,采用邻接表作为有向图的存储结构,并增设一个入度数组indegree[ ]
为了避免每一次选入度为0的顶点时重复扫描入度数组,可以利用栈来存储入度为0的顶点
代码:有详细注释
#include<stdio.h>
#include<stdlib.h>
#define m 100
#define n 6
#define e 8
typedef struct node1 {
int info;
int adjvertex;//这个域就是本节点在数组中的位置
struct node1 *nextarc;
} glinklistnode;//这个是在后面邻接的节点
typedef struct node2 {
int vertexinfo;
glinklistnode *firstarc;
} glinkheadnode;//邻接表的数组,vertexinfo存的是每个点的入度
//数组中的节点比邻接表中的节点多了一个vertexinfo域,用来存储入度值
//创建邻接链表
void createAdjlist(glinkheadnode g[]) {
int i,j,k;
glinklistnode *p;
for(i=0; i<n; i++) {
g[i].vertexinfo=i;
g[i].firstarc=0;
}//初始化每个节点在数组中的位置
for(k=0; k<e; k++) {
scanf("%d%d",&i,&j);//输入两个关联节点
p=(glinklistnode *)malloc(sizeof(glinklistnode));
p->adjvertex=j;
p->nextarc=g[i].firstarc;//使用的插入方式建立,后来的更接近根节点
g[i].firstarc=p;//第一个邻接点是p
}
}
//拓扑排序函数
void toposort(glinkheadnode g[]) {
int i,v,w,sum=0, indegree[n];
struct {
int s[n];
int top;
} stack;//建立一个栈,栈中的s数组用来存入度为0的节点
glinklistnode *p;
for (i=0; i<n; i++) indegree[i]=0;//初始化indegree数组,完全可以使用memset
for (i=0; i<n; i++)
for(p=g[i].firstarc; p!=0; p=p->nextarc) //这一层for循环用来统计
indegree[p->adjvertex]++;//经过两个for循环,即可把所有节点的入度算统计出来
for(i=0,stack.top= -1; i<n; i++) if(indegree[i]==0) {
stack.top++;
stack.s[stack.top]=i;
}//这个for循环用来入栈入度为0的节点
while(stack.top!= -1) {
printf("%d\t",stack.s[stack.top]);
sum=sum+1;
v=stack.s[stack.top];
stack.top=stack.top-1;//出栈top
p=g[v].firstarc;//读取该节点的第一个邻接点
while (p!=0) {//遍历p的所有邻接点
w=p->adjvertex;
indegree[w]=indegree[w]-1;//因为前导节点会被删掉,因此它的入度值需要-1
if (indegree[w]==0) {//如果它的入度等于0,就将这个节点也入栈
stack.top=stack.top+1;
stack.s[stack.top]=w;
}
p=p->nextarc;//往下走
}
}
if(sum<n) printf("The AOV network has a cycle\n");//如果最后输出的节点个数少于总结点数,说明图中有回路
}
int main() {
glinkheadnode g[m];
createAdjlist(g);
toposort(g);
return 0;
}