拓扑排序算法是针对有向无环图(DAG)的一种排序方法,按照它的排序算法最终求得的序列中,一定满足如下条件:若<v0,v1>属于e,e为图的边集,那么就有v0 在 v1的前面。
这样的序列称为拓扑序列,拓扑排序广泛用于一些具有明显优先级的问题中,最典型的应用就是先修和后修课程,如和安排课程,不发生矛盾。注意:拓扑排序算法的基本要求是图汇总不存在环,原因很明显,如果有环就会产生矛盾。那么拓扑排序的步骤是:
1)先将图中每个顶点的入度求出来,保存在数组中
2)利用栈或队列将入度为零的顶点保存
3)设置一个记录循环个数的变量count
4)出栈(任意一个入度为零的顶点),然后将与其相邻的顶点的入度减一,(在图中表示为:将相应的边给除掉),判断减一后的顶点的入度是否为0,若为零则入栈或队列。
5)不断循环步骤4,直至栈或队列为空。
6)判断count与图中顶点个数的大小,若count值小于图中顶点个数,那么就说明图中存在环,不存在拓扑序列。否则存在拓扑序列。
算法结束。
下面是代码:
//图的邻接矩阵表示法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stack>
#include <queue>
using namespace std;
#define Max 100
#define Inf 0x1111
typedef char type;
typedef struct Grap{
type data[Max];
int value[Max][Max];
int n,m;
}Grap,*pgrap;
int Located(pgrap g,char ch){
for(int i=0;i<g->n;i++)
if(g->data[i]==ch)
return i;
}
int invalue[Max];
void Creat_grap(pgrap g){
printf("输入图的顶点数和边数:\n");
scanf("%d%d",&g->n,&g->m);
//printf("ksgfdkj\n");
getchar();
printf("输入图中的顶点:\n");
int i,j;
for(i=0;i<g->n;i++){
g->data[i]=getchar();
getchar();
}
for(i=0;i<g->n;i++)
for(j=0;j<g->n;j++)
g->value[i][j]=Inf;
printf("请输入图中的边:\n");
int index1,index2,value;
char ch1,ch2;
while(g->m--){
scanf("%c,%c,%d",&ch1,&ch2,&value);
getchar();
index1=Located(g,ch1);
index2=Located(g,ch2);
g->value[index1][index2]=value;
//无向图
//g->value[index2][index1]=value;
}
}
void In_value(pgrap g){
memset(invalue,0,sizeof(invalue));
for(int i=0;i<g->n;i++)
for(int j=0;j<g->n;j++)
if(g->value[j][i]!=Inf)
invalue[i]++;
}
void tuopu(pgrap g){
int i;
stack<int> s;
//queue<int> q;
for(i=0;i<g->n;i++)
if(invalue[i]==0)
s.push(i);
int index,count=0;
while(!s.empty()){
index=s.top();
printf("%c ",g->data[index]);
//q.push(index);
s.pop();
count++;
for(i=0;i<g->n;i++)
if(g->value[index][i]!=Inf)
if(--invalue[i]==0)
s.push(i);
}
if(count<g->n)
printf("存在环\n");
}
int main(){
Grap g;
pgrap p=&g;
Creat_grap(p);
In_value(p);
tuopu(p);
return 0;
}
下面是测试数据:
输入图的顶点数和边数:
6 9
输入图中的顶点:
A
B
C
D
E
F
请输入图中的边:
A,B,1
A,C,3
B,D,4
B,C,1
C,D,1
D,E,2
C,E,1
E,F,1
D,F,1
A B C D E F
Terminated with return code 0
Press any key to continue ...
下面是用邻接表是实现的拓扑排序代码:
//图的存储结构
//邻接表
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <stack>
#include <string.h>
using namespace std;
#define Max 100 //顶点个数最多为100个
typedef char type;
typedef struct Arcnode{
int index;
int value;
struct Arcnode *next;
}Arcnode,*parc;
typedef struct Node{
type data;
Arcnode *first;
}Node;
typedef struct Grap{
Node nodetex[Max];
int n; //顶点数
int m; //边数
}Grap,*pgrap;
int invalue[Max];
int Located(pgrap g,char ch){
for(int i=0;i<g->n;i++)
if(ch==g->nodetex[i].data)
return i;
}
void Creat_grap(pgrap g){
printf("输入图的结点数和边数:\n");
scanf("%d%d",&g->n,&g->m);
getchar();
int i,index1,index2,value;
char ch1,ch2;
printf("输入各顶点:\n");
for(i=0;i<g->n;i++){
g->nodetex[i].data=getchar();
g->nodetex[i].first=NULL;
getchar();
}
printf("输入各边及权值:\n");
parc q;
for(i=0;i<g->m;i++){
scanf("%c,%c,%d",&ch1,&ch2,&value);
getchar();
index1=Located(g,ch1);
index2=Located(g,ch2);
q=(parc)malloc(sizeof(Arcnode));
q->index=index2;
q->value=value;
q->next=g->nodetex[index1].first;
g->nodetex[index1].first=q;
//无向图(默认为任意两个顶点之间之多有一条边且自身到自身无边)
/*q=(parc)malloc(sizeof(Arcnode));
q->index=index1;
q->value=value;
q->next=g->nodetex[index2].first;
g->nodetex[index2].first=q;*/
}
}
void Delete_grap(pgrap g){
parc p,q;
for(int i=0;i<g->n;i++){
p=g->nodetex[i].first;
while(p){
q=p->next;
free(p);
p=q;
}
}
}
void In_value(pgrap g){
memset(invalue,0,sizeof(invalue));
for(int i=0;i<g->n;i++){
parc p=g->nodetex[i].first;
while(p){
invalue[p->index]++;
p=p->next;
}
}
}
void tuopu(pgrap g){
stack<int> s;
//queue<int> q;
int i,index,count=0;
for(i=0;i<g->n;i++)
if(invalue[i]==0)
s.push(i);
while(!s.empty()){
index=s.top();
printf("%c ",g->nodetex[index].data);
s.pop();
//q.push(index);
count++;
parc p=g->nodetex[index].first;
while(p){
if(--invalue[p->index]==0)
s.push(p->index);
p=p->next;
}
}
if(count<g->n)
printf("存在环\n");
}
int main(){
Grap g;
pgrap p=&g;
Creat_grap(p);
In_value(p);
tuopu(p);
Delete_grap(p);
return 0;
}
测试数据:
输入图的结点数和边数:
6 9
输入各顶点:
A
B
C
D
E
F
输入各边及权值:
A,B,1
A,C,3
B,D,4
B,C,1
C,D,1
D,E,2
C,E,1
E,F,1
D,F,1
A B C D E F
Terminated with return code 0
Press any key to continue ...