拓扑排序之变量序列算法分析

拓扑排序之变量序列

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo)

题目描述:

假设有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。尽管还有可能其他的可能,你只需找出其中的一个即可。

输入:

输入为一个字符串,其中包含N+N个字符,依次表示N个关系式(1<=N<=100000),例如序列"abcbdc"表示a<b,c<b,d<c.

输出:

给出一个字符串,其中存储了一个符合要求的变量序列,例如,字符串"adcb"表示a<d<c<b。

算法分析:

这是典型的拓扑排序问题。先简单科普一下,所谓拓扑排序,是指将一个有向无环图G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(TopoiSicaiOrder)的序列,简称拓扑序列。

我们先将变量作为顶点输入到图数据结构中。表示图的数据结构有多种,由于本题对应的是稀疏图,应该以边为主要研究对象,所以可以把数据结构设置为邻接表或边表集。

我们先来看邻接表数据结构:

typedef char VertexType; //顶点类型由用户自定义

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

typedef struct EdgeNode{ //边表结点

intadjvex;  //邻接点域,存储该顶点对应的下标

//     EdgeTypeweight; //权值,对于非网图可以不需要

structEdgeNode *next; //链域,指向下一个邻接点

} EdgeNode;

typedef struct VertexNode{ //顶点表结点

VertexTypedata; //顶点域,存储顶点信息

intin;   //存储顶点入度的数量

EdgeNode*firstEdge; //边表头指针

} VertexNode;

由于变量名用单个小写字母表示,我们可以设置一个大小为26的数组存储顶点;又由于26个字母不见得都会出现,故我们设置一个全局变量int book[MAXM]= {0}; 用来标记某字母是否出现。

首先创建一个图,读入顶点和边信息。代码如下:

/*

函数名称:CreateGraph

函数功能:把顶点和边信息读入到表示图的邻接表中

输入变量:char *data:存储了N个关系式的字符串

VertexNode *GL : 顶点表数组

输出变量:表示图的顶点表数组

返回值:int :顶点数量

*/

intCreateGraph(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;

}

拓扑排序算法其实非常简单,只需要搜索入度为0的弧尾顶点,然后将其对应的弧头顶点入度减1,如果该弧头顶点入度也变成了0,就将其存储到栈(或队列)中。搜索的方法有深度优先和广度优先两种。代码分别如下:

/*

函数名称:TopoLogicalSort_DFS

函数功能:拓扑排序,采用深度优先搜索获取拓扑序列

输入变量:char *topo:用来存储拓扑序列的字符串

VertexNode *GL : 顶点表数组

int n:顶点个数

输出变量:用来存储拓扑序列的字符串

返回值:int :拓扑排序成功返回真,若存在环则返回假

*/

int TopoLogicalSort_DFS(char *topo,VertexNode *GL, int n)

{

inti, u, v, top;

intcount = 0; //用于统计输出顶点的个数

EdgeNode*e;

intStack[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)

{

inti, 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小于顶点数,说明存在环

}

我们也可以用边表集来表示图,数据结构如下:

typedef struct Edge{ //边集数组

intu, v; //弧尾和弧头

intnext; //指向同一个弧尾的下一条边

//     EdgeTypeweight; //权值,对于非网图可以不需要

} EdgeLib;

为了表示顶点信息,我们还需要设置两个数组:int In[MAXM], first[MAXM]; //分别存储顶点的入度和第一条边信息。

边表集实现拓扑排序的算法和邻接表非常相似,也是先读入图的顶点和边信息,然后进行拓扑排序。代码如下:

/*

函数名称:CreateGraph_2

函数功能:把顶点和边信息读入到表示图的边表集中

输入变量:char*data:存储了N个关系式的字符串

int In[]:存储了顶点的入度信息

int first[]:指向以该顶点为弧尾的第一条边

EdgeLib edge[]:存储了边信息的边表集

输出变量:表示图的边表集数组

返回值:int :顶点数量

*/

int CreateGraph_2(char *data, int In[], intfirst[], EdgeLib edge[])//创建一个图

{

inti, j;

intcount = 0;//记录顶点数量

for(i=0; i<MAXM; i++)//初始化图

{

first[i]= -1;

book[i]= 0;

In[i]= 0;

}

for(j=i=0; data[i]!=‘\0‘; i+=2,j++)//每次读取两个变量

{

edge[j].u= data[i] - ‘a‘; //字母转换为数字,‘a‘对应0,‘b‘对应1,以此类推

edge[j].v= data[i+1] - ‘a‘;

book[edge[j].u]= book[edge[j].v] = 1;

edge[j].next= first[edge[j].u];

first[edge[j].u]= j;

In[edge[j].v]++;

}

for(i=0; i<MAXM; i++)//计算顶点数量

{

if(book[i] != 0)

count++;

}

returncount;

}

/*

函数名称:TopoLogicalSort

函数功能:拓扑排序,采用广度优先搜索获取拓扑序列

输入变量:char*topo:用来存储拓扑序列的字符串

EdgeLib edge[]:存储了边信息的边表集

int In[]:存储了顶点的入度信息

int first[]:指向以该顶点为弧尾的第一条边

int n:顶点个数

输出变量:用来存储拓扑序列的字符串

返回值:int :拓扑排序成功返回真,若存在环则返回假

*/

int TopoLogicalSort(char *topo, EdgeLibedge[], int In[], int first[], int n)

{

inti, u, front, rear;

front= rear = 0;

for(i=0; i<MAXM; i++)//将入度为0的顶点入栈

{

if(book[i] != 0 && In[i] == 0)

{

topo[rear++]= i + ‘a‘;

}

}

while(front < rear)//采用广度优先搜索获取拓扑序列

{

u= topo[front++] - ‘a‘;

for(i=first[u]; i!=-1; i=edge[i].next)

{

if(--In[edge[i].v] == 0)

topo[rear++]= edge[i].v + ‘a‘;

}

}

topo[rear]= ‘\0‘;

return(rear == n);//如果count小于顶点数,说明存在环

}

这里只给出了相关函数,完整的测试代码请到巧若拙的博客(http://blog.csdn.net/qiaoruozhuo)查看。

时间: 2024-10-06 01:20:24

拓扑排序之变量序列算法分析的相关文章

拓扑排序之变量序列代码

/* 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.尽管还有可能其他的可能,你只需找出其中的一个即可. In

7-9-有向图无环拓扑排序-图-第7章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第7章  图 - 有向无环图拓扑排序 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h.SequenceStack.c.ALGraph.c    

HDU 1285 确定比赛名次(拓扑排序基础)

题目大意: 题目是说,给你一个n个节点的有向无环图,然后,对于这个无环图,我们对他进行拓扑排序,使得拓扑排序中的序列按照字典序的方式输出. 解题思路: 直接套用toposort()模板... 先说说toposort()的含义: 拓扑排序就是说,我们在一完成一项工程的时候,这个工程分为了很多的子工程,我们不可能每次都一下完成很多的工程,我们要按照一定事 务之间的内在联系来完成相应的工程,比如你要完成A工程,那么你必须先完成B工程,所以说B的优先级高于A.那么我们有建图.. 代码: 1 # incl

算法导论22.4拓扑排序 练习总结 (转载)

22.4-1 给出算法 TOPOLOGICAL-SORT 运行于图 22-8 上时所生成的结点次序.这里的所有假设和练习 22.3-2 一样. ANSWER:   22.4-2 请给出一个线性时间的算法,算法的输入为一个有向无环图 G = (V, E) 以及两个结点 s 和 t,算法的输出是从结点 s 到结点 t 之间的简单路径的数量.例如,对于图 22-8 所示的有向无环图,从结点 p 到结点 v 一共有 4 条简单路径,分别是 pov.poryv.posryv 和 psryv.(本题仅要求计

HDU-1285 简单拓扑排序

确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 35253    Accepted Submission(s): 13787 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直

拓扑排序获取所有可能序列JAVA实现

在看算法基础这本书,看到有向无环图,其中介绍到了拓扑排序,讲到了获取拓扑序列的方法,结合自己的理解,用JAVA代码实现了获取所有可能序列,水平有限,效率什么的就没有考虑,下面贴上代码: package graphics.dag.topologicalsort; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 有向无环图所有的走法 * @author zhangxinren * */

拓扑排序 判断给定图是否存在合法拓扑序列 自家oj1393

1 //拓扑排序判断是否有环 2 #include<cstdio> 3 #include<algorithm> 4 #include<string.h> 5 #include<math.h> 6 #include<queue> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=1e2+10; 10 int G[maxn][maxn]; 11 int in[maxn];

数据结构:拓扑排序之 确定比赛名词

[BestCoder Round #3 来了!]8月3号19:00~21:00(赛前30分钟停止注册比赛) 确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11642    Accepted Submission(s): 4634 Problem Description 有 N个比赛队(1<=N<=500),编号依次为1,

UVA10305 Ordering Tasks【DFS】【拓扑排序】

Ordering Tasks Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB John has n tasks to do. Unfortunately, the tasks are not independent and the execution of one task is only possible if other tasks have already been