一.关于拓扑排序的背景
根据我的的理解,一些事件的发生顺序是互相联系的,比如事件A需要在事件B发生完毕之后才可能发生,可以说B是A的前驱事件。
例如大学中的课程设置,要学习算法设计这么课程,就要先学习数据结构。因此,我们上课的顺序是依赖某些课程之间的关系的,当然,这种顺序并不唯一,例如计算机网络和计算机组成原理之间没有先后关系。
但我们学习课程仍然要一定的顺序,计算机网络可能先学,计算机组成原理也可能先学。
抽象出来,这些课程就是图中的点,有向的边表示了这种前驱关系。
我们需要根据”图“来生成一种线性的顺序,当然,可能不唯一,但只要其中一种即可。
需要注意的是,这种情况下,图中不能有环路,假设要学计算机组成原理必须先学操作系统,要学操作系统又必须先学计算机网络,要学计算机网络有要学计算机组成原理(假设)那么,我们就不知道该从哪门学起。所以图中不能有环路,而且容易想到,必定至少有一个点是入度为0的,也就是说必须有某门课程不需要先学其它课程,这样我们才能开始学习。
二.算法设计
如刚才所述,我们可以先找到一个入度为零的点,这个点自然是将要生成顺序的第一个点。然后将这个点删除,由这个点出发的边也删除,然后寻找下一个入度为零的点。(剩下的图也必然为有向无环图)可以以队列的方式存储,先将点1加入队列,将点1的出边删除,然后将新的入度为0的点加入队列,再让点1出队,如此循环,直到队列为空。依次出队的点保存,即为一个拓扑顺序。
至于图,用二维矩阵存储
三.用C语言描述
//关于拓扑排序的一个算法:起始点必然是入度为零的点,删除起始点,第二个点也必然是入度为零的点,以此类推,以队列存储,队列为空时,算法结束
//关于拓扑排序的一个算法:起始点必然是入度为零的点,删除起始点,第二个点也必然是入度为零的点,以此类推,以队列存储,队列为空时,算法结束
#include <stdio.h>
#define Max 99999999
int graph[11][11];
void init(int n) //初始化图
{
int i, j;
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
{
if(i == j)
graph[i][j] = 0;
else
graph[i][j] = Max;
}
return;
}
void get(int m) //输入图的函数,传递边的数量
{
int i, t1, t2;
printf("please input the graph:\n");
for(i = 1; i <= m; i++)
{
scanf("%d %d",&t1, &t2);
graph[t1][t2] = 1;
}
}
int Is_Origin(int n,int clown) //传递图的大小,以及某一列,若该列全部为Max(除本身),则说明其它点不能连到该点,即其入度为零,则该列所在的点为一个起始点
{
int i, flag = 1;
for(i = 1; i <= n; i++)
{
if(i == clown)
continue;
if(graph[i][clown] == 1) //有其它点连接到该点
{
flag = 0;
break;
}
}
return flag;
}
void DeleteEdge(int n, int row) //删除某点的所有出边
{
int i;
for(i = 1; i <= n; i++)
{
graph[row][i] = Max;
}
}
int main()
{
int queue[100]; //创建一个队列
int front = 0;
int rear = 0;
int book[10] = {0}; //标记结点是否已在队列中
int seq[10] = {0}; //保留拓扑排序的结果
int i,n,m, count = 0;
printf("please input the size of the graph:\n");
scanf("%d",&n);
init(n);
printf("please input the number of the edge:\n");
scanf("%d",&m);
get(m);
//开始寻找入度为零的点
for(i = 1; i <= n; i++)
{
if(Is_Origin(n,i)) //如果该点是起始点,加入到队列
{
queue[rear++] = i;
seq[++count] = i;
book[i] =1; //结点i已入队
}
}
while(front != rear) //队列不为空
{
//队首出队,删除结点
DeleteEdge(n, queue[front]);
front++;
//再次寻找是否有入度为零的点,加入到队列中
for(i = 1; i <= n; i++)
{
if(book[i] == 0)
{
if(Is_Origin(n, i))
{
queue[rear++] = i;
book[i] = 1;
seq[++count] = i;
}
}
}
}
if(count != n)
{
printf("the graph has a loop!\n");
}
else
{
for(i = 1; i <= n; i++)
printf("%3d",seq[i]);
}
getchar();
getchar();
return 0;
}