拓扑排序之变量序列(三种算法实现)

/*
Name: 拓扑排序之变量序列(三种算法实现) 
Copyright: 
Author: 
Date: 17-11-14 21:02
Description: 拓扑排序之变量序列 
假设有n个变量(1<=n<=26,变量名用单个小写字母表示),还有m个二元组(u,v),分别表示变量u小于v。
那么,所有变量从小到大排列起来应该是什么样子的呢?
例如有4个变量a,b,c,d,若以知a<b,c<b,d<c,则这4个变量的排序可能是a<d<c<b。
尽管还有可能其他的可能,你只需找出其中的一个即可。
Input
输入为一个字符串data,其中包含N+N个字符,表示N个关系式(1<=N<=100000),例如序列"abcbdc"表示a<b,c<b,d<c.
Output
给出一个字符串,其中存储了一个符合要求的变量序列,例如,字符串"adcb"表示a<d<c<b。 

算法分析:
拓扑序列存在的充要条件是能构成一个有向无环图,有两种思路生成拓扑序列:
一是深度优先搜索图,遍历u的邻接点,查看是否存在反向边,若有反向边则说明存在环,不能生成拓扑序列;
否则在访问结点结束后,将结点纳入拓扑序列,注意此时存储的是一个逆序的拓扑序列,需要逆序操作。 
二是查看入度为0的结点,将其纳入拓扑序列(有存储到栈或队列两种方式),然后将其邻接点的入度减一,
若邻接点入度减一后入度变成0了,则将其纳入拓扑序列。
最后查看是否所有结点都纳入了拓扑序列,如果有遗漏结点,说明存在环。 

*/
#include<stdio.h>
#include<stdlib.h>


#define true 1  
#define false 0
#define MAXM 26   //最大变量(顶点)数量 
#define MAXN 100000   //最大关系式数量 


typedef char VertexType; //顶点类型由用户自定义
typedef int EdgeType; //边上的权值类型由用户自定义


typedef struct EdgeNode{ //边表结点
int adjvex;  //邻接点域,存储该顶点对应的下标
// EdgeType weight; //权值,对于非网图可以不需要 
struct EdgeNode *next; //链域,指向下一个邻接点 
} EdgeNode;


typedef struct VertexNode{ //顶点表结点
VertexType data; //顶点域,存储顶点信息
int in;   //存储顶点入度的数量 
EdgeNode *firstEdge; //边表头指针
} VertexNode;

int book[MAXM] = {0}; //标记某字母是否出现 
int color[MAXM] = {0};//存储顶点的颜色,白色(0)表示未访问,灰色(1)表示已访问,黑色(2)表示已完成访问 

int IsTopoSeq(char *data, char *topo);//根据关系列表data,判断topo字符串是否为拓扑序列 
int CreateGraph(char *data, VertexNode *GL);//创建一个图
void PrintGraph(VertexNode *GL);//输出图
int TopoLogicalSort_DFS(char *topo, VertexNode *GL, int n);//拓扑排序,获取拓扑序列,若存在环则返回假 
int TopoLogicalSort_BFS(char *topo, VertexNode *GL, int n);//拓扑排序,获取拓扑序列,若存在环则返回假 
int TopoLogicalSort_DFS_COLOR(char *topo, VertexNode *GL, int n);//拓扑排序,获取拓扑序列,若存在环则返回假 
int DFS_COLOR(char *topo, VertexNode *GL, int *top, int u);//使用深度优先搜索方法构造逆序拓扑序列 

int main()
{
	int i, n;
	VertexNode GL[MAXM];
	char topo[MAXM+1];
	char data[MAXN+MAXN+1];
	int In[MAXM], first[MAXM]; //存储顶点信息

///	采用广度优先搜索获取拓扑序列
	gets(data); 
	n = CreateGraph(data, GL);//创建一个图
	PrintGraph(GL);//输出图
		
	if (TopoLogicalSort_BFS(topo, GL, n))//采用拓扑排序构造拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 
	
	if (IsTopoSeq(data, topo))//根据关系列表data,判断topo字符串是否为拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 
		
//	采用深度优先搜索获取拓扑序列	
	gets(data); 
	n = CreateGraph(data, GL);//创建一个图
	PrintGraph(GL);//输出图
		
	if (TopoLogicalSort_DFS(topo, GL, n))//采用拓扑排序构造拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 
	
	if (IsTopoSeq(data, topo))//根据关系列表data,判断topo字符串是否为拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 

/采用深度优先搜索判断反向边算法获取拓扑序列
    gets(data); 
	n = CreateGraph(data, GL);//创建一个图
	PrintGraph(GL);//输出图
	
	if (TopoLogicalSort_DFS_COLOR(topo, GL, n))//采用拓扑排序构造拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 
		
	if (IsTopoSeq(data, topo))//根据关系列表data,判断topo字符串是否为拓扑序列 
	   puts(topo);
	else
		puts("不存在满足条件的序列"); 
	
	
    
    system("pause");
    return 0;
}
/*
函数名称:CreateGraph
函数功能:把顶点和边信息读入到表示图的邻接表中 
输入变量:char *data:存储了N个关系式的字符串 
          VertexNode *GL : 顶点表数组 
输出变量:表示图的顶点表数组 
返回值:int :顶点数量 
*/ 
int CreateGraph(char *data, VertexNode *GL)
{
	int i, u, v;
	int count = 0;//记录顶点数量 
	EdgeNode *e;
	
	for (i=0; i<MAXM; i++)//初始化图 
	{
		GL[i].data = i + 'a';
		GL[i].in = 0;
		GL[i].firstEdge = NULL;
		book[i] = 0;
	}
	
	for (i=0; data[i]!='\0'; i+=2)//每次读取两个变量  
	{
		u = data[i] - 'a'; //字母转换为数字,'a'对应0,'b'对应1,以此类推 
		v = data[i+1] - 'a';
		book[u] = book[v] = 1;
		
		e = (EdgeNode*)malloc(sizeof(EdgeNode)); //采用头插法插入边表结点 
		if (!e)
		{
			puts("Error"); 
			exit(1);
		}
		e->adjvex = v;
		e->next = GL[u].firstEdge;
		GL[u].firstEdge = e;
		
		GL[v].in++;
	}
	
	for (i=0; i<MAXM; i++)//计算顶点数量 
	{
		if (book[i] != 0)
		   count++;
	}
	
	return count;
} 


void PrintGraph(VertexNode *GL)//输出图
{
	int u, v;
	EdgeNode *e;
	
	for (u=0; u<MAXM; u++)
	{
		printf("G[%d] = %c: ", u, GL[u].data);
		for (e=GL[u].firstEdge; e!=NULL; e=e->next)//将u的邻接点入度减1,并将入度为0的顶点入栈 
		{
			v = e->adjvex;
			printf("<%c, %c>, ", GL[u].data, GL[v].data);
		}
		printf("\n");
	}
	printf("\n");
} 


/*
函数名称:TopoLogicalSort_DFS
函数功能:拓扑排序,采用深度优先搜索获取拓扑序列
输入变量:char *topo:用来存储拓扑序列的字符串 
          VertexNode *GL : 顶点表数组 
          int n:顶点个数 
输出变量:用来存储拓扑序列的字符串
返回值:int :拓扑排序成功返回真,若存在环则返回假
*/ 
int TopoLogicalSort_DFS(char *topo, VertexNode *GL, int n)
{
	int i, u, v, top;
	int count = 0; //用于统计输出顶点的个数 
	EdgeNode *e;
	int Stack[MAXM];
	
	for (top=i=0; i<MAXM; i++)//将入度为0的顶点入栈 
	{
		if (book[i] != 0 && GL[i].in == 0)
		{
		    Stack[top++] = i;
		}
	}
	
	while (top > 0)//采用深度优先搜索获取拓扑序列 
	{
		u = Stack[--top];
		topo[count++] = u + 'a';
		
		for (e=GL[u].firstEdge; e!=NULL; e=e->next)//将u的邻接点入度减1,并将入度为0的顶点入栈 
		{
			v = e->adjvex;
			if (--GL[v].in == 0)
				Stack[top++] = v;
		}
	}
	topo[count] = '\0';
	
	return (count == n);//如果count小于顶点数,说明存在环 
}

/*
函数名称:TopoLogicalSort_BFS
函数功能:拓扑排序,采用广度优先搜索获取拓扑序列
输入变量:char *topo:用来存储拓扑序列的字符串 
          VertexNode *GL : 顶点表数组 
          int n:顶点个数 
输出变量:用来存储拓扑序列的字符串
返回值:int :拓扑排序成功返回真,若存在环则返回假
*/ 
int TopoLogicalSort_BFS(char *topo, VertexNode *GL, int n)
{
	int i, u, v, front, rear;
	EdgeNode *e;
	
	front = rear = 0;
	for (i=0; i<MAXM; i++)//将入度为0的顶点入栈 
	{
		if (book[i] != 0 && GL[i].in == 0)
		{
			topo[rear++] = i + 'a';
		}
	}
	
	while (front < rear)//采用广度优先搜索获取拓扑序列 
	{
		u = topo[front++] - 'a';
		
		for (e=GL[u].firstEdge; e!=NULL; e=e->next)//将u的邻接点入度减1,并将入度为0的顶点入栈 
		{
			v = e->adjvex;
			if (--GL[v].in == 0)
				topo[rear++] = v + 'a';
		}
	}
	topo[rear] = '\0';
	
	return (rear == n);//如果count小于顶点数,说明存在环 
}

int IsTopoSeq(char *data, char *topo)//根据关系列表data,判断topo字符串是否为拓扑序列 
{
	int pos[MAXM] = {0};
	int i;
	
	for (i=0; topo[i]!='\0'; i++)//读取变量下标
		pos[topo[i]-'a'] = i;
	
	for (i=0; data[i]!='\0'; i+=2)//每次读取两个变量  
	{
		if (pos[data[i]-'a'] > pos[data[i+1]-'a'])
		   return false;
	}
	
	return true;
}

/*
函数名称:TopoLogicalSort_DFS
函数功能:拓扑排序,采用深度优先搜索判断反向边算法获取拓扑序列
输入变量:char *topo:用来存储拓扑序列的字符串 
          VertexNode *GL : 顶点表数组 
          int n:顶点个数 
输出变量:用来存储拓扑序列的字符串
返回值:int :拓扑排序成功返回真,若存在环则返回假
*/ 
int TopoLogicalSort_DFS_COLOR(char *topo, VertexNode *GL, int n)
{
    int i, temp, top = 0;
    int flag = 1;
    
    for (i=0; i<MAXM; i++) //获得一个逆序的拓扑序列 
    {
        if (book[i] != 0 && color[i] == 0)
        {
            flag = DFS_COLOR(topo, GL, &top, i);
        }
    }
    
    for (i=0,top--; i<=top; i++, top--) //改变拓扑序列的顺序 
    {
	 	temp = topo[top];
	 	topo[top] = topo[i] + 'a';
	 	topo[i] = temp + 'a';
	}
    
    topo[n] = '\0'; 
    return flag;
}

int DFS_COLOR(char *topo, VertexNode *GL, int *top, int u)//使用深度优先搜索方法构造逆序拓扑序列 
{ 
  	int i;
 	EdgeNode *e;
 	int flag = 1;
 	
 	color[u] = 1; //printf("(%c", u+'a');
 	for(e=GL[u].firstEdge; e!=NULL; e=e->next)//遍历u的邻接点,查看是否存在反向边 
    {
        if (color[e->adjvex] == 1 || flag == 0)//如果有反向边,说明存在环 
        {
		    return 0;
		}
  		if (color[e->adjvex] == 0)
    	{
            flag = DFS_COLOR(topo, GL, top, e->adjvex);
        }
    }
    color[u] = 2; //printf("%c)", u+'a');
	topo[(*top)++] = u;  //加入拓扑序列,注意是逆序   
	
	return flag;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值