拓扑排序是对有向无圈图的顶点的一种排序,它使得如果存在一条从vi到vj的路径,那么在排序中Vj出现在Vi后面。一个简单的求拓扑排序的算法是先找出任意一个没有入边的顶点,然后我们显示该顶点,并将它和它的边一起从图中删除。然后为们对图的其余部分应用同样的方法处理。但是这个方法有一点不好,就是每次都要找入度为0的顶点,这种顶点一般很少,如果图很大的话,每次都遍历一遍就浪费很多时间。升级版是先计算每一个顶点的入度,然后将入度为0的顶点存入队列,操作完之后再更新入度。这样就不用遍历整个图而只需要从出队列操作就可以了。下面是代码,队列的操作在上一篇文章中已经实现,只要把类型改成节点的指针即可。
topSort.h
#ifndef __TOPSORT_H
#define __TOPSORT_H
struct graph;
struct listNode;
typedef struct graph *Graph;
typedef struct listNode *Vertex;
struct graph
{
int numberOfVertex;
Vertex *vertexs;
};
struct listNode
{
int indegree;
int vertexnumber;
Vertex next;
};
void topSort(Graph G);
Graph initinalizeAdjList(int listSize);
Graph insertAdjList(Graph G,int pos,int a[],int N);
#endif
topSort.c
#include "topSort.h"
#include "queue.h"
void topSort(Graph G)
{
Queue Q;
Vertex V,W;
int counter=0;
int i;
Q=createQueue();
for(i=1;i<=G->numberOfVertex;i++)<span style="white-space:pre"> </span>//找到入度为0的点,将它们入队列
{
if(G->vertexs[i]->indegree==0)
EnQueue(G->vertexs[i],Q);<span style="white-space:pre"> </span>
}
while(!isEmpty(Q))<span style="white-space:pre"> </span>//删除该点,然后将其相邻的点入度减1,再重新检测入队列
{
V=DeQueue(Q);
printf(" %d ",V->vertexnumber);
counter++;
for(i=1;i<=G->numberOfVertex;i++)
{
if(isAdj(G->vertexs[i],V))
{
if((--G->vertexs[i]->indegree)==0)
EnQueue(G->vertexs[i],Q);
}
}
}
if(counter!=G->numberOfVertex)
{
printf("Graph has a cycle\n");
exit(-1);
}
deleteQueue(Q);
}
Graph initinalizeAdjList(int listSize)<span style="white-space:pre"> </span>//初始化一个邻接表,就是创建一个指针数组,每个元素只想一个节点
{
Graph G;
int i;
G=(Graph)malloc(sizeof(struct graph));
if(G==NULL)
{
printf("out of space\n");
exit(-1);
}
G->numberOfVertex=listSize;
G->vertexs=(Vertex*)malloc(sizeof(Vertex)*(listSize+1));
for(i=1;i<=listSize;i++)<span style="white-space:pre"> </span>//这里简单的直接给出节点编号,实际中可以用哈希的方法来获得
{
G->vertexs[i]=(Vertex)malloc(sizeof(struct listNode));<span style="white-space:pre"> </span>//初始化节点
G->vertexs[i]->vertexnumber=i;
G->vertexs[i]->next=NULL;
}
return G;
}
Graph insertAdjList(Graph G,int pos,int a[],int N)<span style="white-space:pre"> </span>//根据给出的数组来给邻接表插入元素
{
int j;
Vertex v,w;
G->vertexs[pos]->indegree=N;
w=G->vertexs[pos];
for(j=0;j<N;j++)
{
v=(Vertex)malloc(sizeof(struct listNode));
v->vertexnumber=a[j];
v->next=NULL;
while(w->next)
w=w->next;
w->next=v;
}
}
int isAdj(Vertex v,Vertex w) //if v adj w<span style="white-space:pre"> </span>判断是不是和目标节点相邻
{
Vertex t;
t=v->next;
while(t)
{
if(t->vertexnumber==w->vertexnumber)
return 1;
t=t->next;
}
return 0;
}
main.c
#include "queue.h"
#include "topSort.h"
int main()
{
Graph G;
int i;
int a1[]={2,4,3};
int a2[]={4,5};
int a3[]={6};
int a4[]={6,7,3};
int a5[]={4,7};
int a7[]={6};
G=initinalizeAdjList(7);
insertAdjList(G,1,a1,3);
insertAdjList(G,2,a2,2);
insertAdjList(G,3,a3,1);
insertAdjList(G,4,a4,3);
insertAdjList(G,5,a5,2);
insertAdjList(G,6,a5,0);
insertAdjList(G,7,a7,1);
for(i=1;i<=7;i++)
{
Vertex v;
v=G->vertexs[i];
while(v)
{
printf(" %d ",v->vertexnumber);
v=v->next;
}
printf("\n");
}
topSort(G);
}