拓扑排序

拓扑排序:即对有向无环图进行排序,使得排序后所得系列满足如下条件,凡是是<s,t>属于DAG图则有s在序列中位于t的前方,这样得到的序列称为拓扑排序序列,那么有两种方法构建拓扑排序。条件是:该有向图必须是无环图即DAG图。

一种是Kahn算法:(伪代码)

L← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    foreach node m with an edge e from nto m do
        remove edge e from thegraph
        ifm has no other incoming edges then
            insert m into S
if graph has edges then
    return error (graph has at least onecycle)
else
    return L (a topologically sortedorder)

 

该算法的核心是将原图中入度为0的顶点存入栈或队列,然后任意取出一个顶点,去点这个顶点以及与其相连的所有边,如果与其相连的顶点的入度在去掉这条边后入度为0则入栈或队列,不断循环执行,最终判断图中是否还有没有去掉的边,如有则至少存在一个环,否则排序成功。

下面是代码:

#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
#define Max 101
typedef int type_data;
int coun[Max]; //入度记录数组
int record[Max-1];//拓扑排序系列
//bool visit[Max];
typedef struct Arc{ //边结点
	int number;
	int value;
	struct Arc *next;
}ArcNode;
typedef struct{ //表头结点
	type_data data;
	ArcNode *first;
}VertexNode;
typedef struct{ //图
	int n;//结点数
	int m;//边数
	VertexNode tex[Max];
}AdjList;
void Creat_grap(AdjList *g){
	scanf("%d%d",&g->n,&g->m);
	memset(coun,0,sizeof(coun));
	int i,s,t,val;
	for(i=1;i<=g->n;i++){
		scanf("%d",&g->tex[i].data);
		g->tex[i].first=NULL;
	}
	for(i=0;i<g->m;i++){
		scanf("%d%d%d",&s,&t,&val);
		coun[t]++;
		ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));
        p->number=t;
        p->value=val;
        p->next=g->tex[s].first;
        g->tex[s].first=p;
       /* ArcNode *q=(ArcNode*)malloc(sizeof(ArcNode));  //当为有向图时不能写
        q->number=s;
        q->value=val;
        q->next=g->tex[t].first;
        g->tex[t].first=q;*/
		
	}
}
void Clear(AdjList *g){
	for(int i=1;i<=g->n;i++){
		ArcNode *p=g->tex[i].first;
		while(p){
			ArcNode *q=p->next;
			free(p);
			p=q;
		}
	}
}

bool Insert_kahn(AdjList *g){
	queue<int> que;
	for(int i=1;i<=g->n;i++)
		if(coun[i]==0)
			que.push(i);
	int num=0,index=0;
	while(!que.empty()){
		int temp=que.front();
		que.pop();
		record[index++]=temp;
		ArcNode *q=g->tex[temp].first;	
		while(q){
			if(--coun[q->number]==0)
				que.push(q->number);
			q=q->next;
			num++;
		}
	}
	if(num<g->m){
		printf("having a circle\n");
		return false;
	}
	return true;
}

int main(){
	AdjList g;
	Creat_grap(&g);
	/*for(int i=1;i<=g.n;i++){
		//printf("skjdfhsdkh\n");
	ArcNode *p=g.tex[i].first;
    while(p){
		printf("%d ",p->number);
		p=p->next;
	}
	printf("\n");
	}
	Ebfs(&g);
	Clear(&g);*/
	if(Insert_kahn(&g))
		for(int i=0;i<g.n;i++)
			printf("%d ",record[i]);
	Clear(&g);
	return 0;
}

另一种方法为dfs的方法,那么这种方法的前提是已知图为DAG才可排序,否则会出错,基于这种算法的图的存储结构也由原来的临界表转换为邻接矩阵,给算法的核心是:

用栈或者队列存储出度为0的顶点,设置标记数组,如没有访问则访问,而访问则用dfs函数实现,对于该函数提供的每一个顶点,遍历所有顶点,若遍历的顶点没有指向该顶点
并且没有访问,则递归访问,在遍历完后还要讲提供顶点如栈或队列。

下面是伪代码:

L ← Empty list that will contain the sorted nodes
S ← Set of all nodes with no outgoing edges
for each node n in S do
    visit(n)
function visit(node n)
    if n has not been visited yet then
        mark n as visited
        for each node m with an edgefrom m to ndo
            visit(m)
       add n to L

下面是不完整代码(供参考):

#include <queue>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
using namespace std;
#define Max 101
typedef int type_data;
bool coun[Max]; //出度记录数组
//int record[Max-1];//拓扑排序系列
queue<int> record;
bool visit[Max];
//bool visit[Max];
typedef struct Arc{ //边结点
	int number;
	int value;
	struct Arc *next;
}ArcNode;
typedef struct{ //表头结点
	type_data data;
	ArcNode *first;
}VertexNode;
typedef struct{ //图
	int n;//结点数
	int m;//边数
	VertexNode tex[Max];
}AdjList;
void Creat_grap(AdjList *g){
	scanf("%d%d",&g->n,&g->m);
	memset(coun,0,sizeof(coun));
	int i,s,t,val;
	for(i=1;i<=g->n;i++){
		scanf("%d",&g->tex[i].data);
		g->tex[i].first=NULL;
	}
	for(i=0;i<g->m;i++){
		scanf("%d%d%d",&s,&t,&val);
		coun[s]=true;
		ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));
        p->number=t;
        p->value=val;
        p->next=g->tex[s].first;
        g->tex[s].first=p;
       /* ArcNode *q=(ArcNode*)malloc(sizeof(ArcNode));  //当为有向图时不能写
        q->number=s;
        q->value=val;
        q->next=g->tex[t].first;
        g->tex[t].first=q;*/
		
	}
}
void Clear(AdjList *g){
	for(int i=1;i<=g->n;i++){
		ArcNode *p=g->tex[i].first;
		while(p){
			ArcNode *q=p->next;
			free(p);
			p=q;
		}
	}
}

void dfs(AdjList *g,int num){
	visit[num]=true;
	for(int i=1;i<=g->n;i++){
		if(!i:adj[num] && !visit[i])
			dfs(g,q->number);
	}
	record.push(num);
}

void Insert_Edfs(AdjList *g){
	queue<int> que;
	memset(visit,0,sizeof(visit));
	for(int i=1;i<=g->n;i++)
		if(!coun[i])
			que.push(i);
	while(!que.empty()){
		int temp=que.front();
		que.pop();
		if(!visit[temp])
			dfs(g,temp);
	}
}

int main(){
	AdjList g;
	Creat_grap(&g);
	Insert_Edfs(&g);
	Clear(&g);
	return 0;
}
				
		
	
        			


 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值