1.拓扑排序介绍
拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。这样说,可能理解起来比较抽象。下面通过简单的例子进行说明!
例如,一个项目包括A、B、C、D四个子部分来完成,并且A依赖于B和D,C依赖于D。现在要制定一个计划,写出A、B、C、D的执行顺序。这时,就可以利用到拓扑排序,它就是用来确定事物发生的顺序的。
在拓扑排序中,如果存在一条从顶点A到顶点B的路径,那么在排序结果中B出现在A的后面。
2.拓扑排序算法步骤
注:顶点A没有依赖顶点,是指不存在以A为终点的边。
-
构造一个队列Q(queue) 和 拓扑排序的结果队列T(topological);
-
计算所有顶点的依赖个数(入度)
-
把所有没有依赖顶点的节点放入Q;
-
当Q内还有顶点的时候,执行下面步骤:
4.1 从Q中取出一个顶点n(将n从Q中删掉),并放入T(将n加入到结果集中);
4.2 使顶点n的指向邻接点m(n是起点,m是终点);
执行以下步骤:
去掉边<n,m>;此时m的依赖-1.
如果m没有依赖顶点,则把m放入Q;直到顶点n没有邻接点,跳出4.2
直到所有顶点的依赖都消掉,依次将Q内剩余的顶点放入T中
3.代码
1.基本定义
由邻接表实现
typedef struct eNode {
int adjVer; //该边的邻接点编号
int weight; //该边的的信息,如权值
struct eNode* nextEdge; //指向下一条边的指针
}EdgeNode; //别名,边结点的类型
typedef struct vNode {
EdgeNode* firstEdge; //指向第一个边结点
}VNode; //别名,邻接表的头结点类型
typedef struct list {
int n; //顶点个数
int e; //边数
VNode adjList[MAXV]; //邻接表的头结点数组
}ListGraph; //别名,完整的图邻接表类型
2.拓扑排序
void topological(ListGraph* LG){
int i,j;
int index = 0; //拓扑排序结果数组的索引
int head = 0; //辅助队列的头
int rear = 0; //辅助队列的尾
int *queue; //辅助队列
int *ins; //记录入度个数的队列
int *tops; //拓扑排序结果数组,记录每个节点的排序后的序号。
int n = LG->n;
EdgeNode *p;
ins = (int *)malloc(n*sizeof(int)); // 入度数组
tops = (int *)malloc(n*sizeof(int));// 拓扑排序结果数组
queue = (int *)malloc(n*sizeof(int)); // 辅助队列
assert(ins!=NULL && tops!=NULL && queue!=NULL);
memset(ins, 0, n*sizeof(int));
memset(tops, 0, n*sizeof(char));
memset(queue, 0, n*sizeof(int));
//统计每个顶点的入度数
for (i = 0; i < n; ++i) {
p = LG->adjList[i].firstEdge;
while (p != NULL){
ins[p->adjVer]++;
p = p->nextEdge;
}
}
//将所有入度为0的顶点入队列
for ( i = 0; i < n; ++i) {
if (ins[i]==0){
queue[rear++] = i;
}
}
while (head != rear){ //队列非空
j = queue[head++]; // 出队列。j是顶点的序号
tops[index++] = j; // 将该顶点添加到tops中,tops是排序结果,index=0
p = LG->adjList[j].firstEdge; // 获取以该顶点为起点的出边队列
// 将与"p"关联的节点的入度减1;
// 若减1之后,该节点的入度为0;则将该节点添加到队列中。
while (p != NULL){
ins[p->adjVer]--; // 将节点(序号为p->adjVer)的入度减1。
if (ins[p->adjVer]==0){
queue[rear++] = p->adjVer; //入队
}
p = p->nextEdge; //循环下一个以顶点p为起点的p->adjVer
}
}
if(index != LG->n){ //有的依赖去不掉
printf("图中有环"); //这是检验是否使有环图的方法
}else{
printf("== TopSort: ");
for(i = 0; i < n; i ++)
printf("%c ", tops[i]);
printf("\n");
}
free(queue);
free(ins);
free(tops);
}