拓扑排序算法

拓扑排序算法解析
本文详细介绍了拓扑排序算法的概念及其应用,特别是针对有向无环图(DAG)。通过两个具体的实现案例——邻接矩阵和邻接表,展示了如何进行拓扑排序,并提供了完整的源代码及测试数据。

拓扑排序算法是针对有向无环图(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 ...

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值