拓扑排序

来源:互联网 发布:怎么注册野火软件 编辑:程序博客网 时间:2024/05/21 17:10

相关定义和术语:

集合: 数据元素间的关系是同属一个集合。

线性结构:结点间的关系是线性关系,除开始结点和终端结点外,每个结点只有一个直接前趋和直接后继。

树形结构:结点间的关系实质上是层次关系,同层上的每个结点可以和下一层的零个或多个结点(即孩子)相关,但只能和上一层的一个结点(即双亲)相关(根结点除外)。

图(Graph)结构:对结点(图中常称为顶点)的前趋和后继个数不加限制的,即结点之间的关系是任意的。 图是一种较线性表和树更为复杂的非线性结构。是对结点的前趋和

后继个数不加限制的数据结构,用来描述元素之间“多对多”的关系。


1   图及其基本运算 

图的定义 :

图是由一个顶点集 V 和一个弧集 R构成的数据结构。           

Graph = (V, R )

V = { x | x  某个数据对象} , 是顶点的有穷非空集合;

 R——边的有限集合

 R = {(x, y) | x, y  V }  无向图      或

 R = {<x, y> | x, y  V && Path (x, y)}有向图是顶点之间关系的有穷集合,也叫做边(edge)集合。Path (x, y)表示从 x 到 y 的一条单向通路, 它是有方向的。x弧尾,y弧头。

有向图与无向图 :

有向图中:边用<x, y>表示,且x与y是有序的。

a.   有向图中的边称为“弧”

b.   x——弧尾或初始点   y——弧头或终端点

无向图:边用(x, y) 表示,且顶x与 y是无序的。

完全图:

在具有n 个顶点的有向图中,最大弧数为 n(n-1) 

在具有n 个顶点的无向图中,最大边数为 n(n-1)/2

顶点的度:

无向图:与该顶点相关的边的数目

有向图:入度ID(v) :以该顶点为头的弧的数目

出度OD(v) :以该顶点为尾头的弧的数目

在有向图中, 顶点的度等于该顶点的入度与出度之和。


上图中,图(a)为无向图,其中G1的顶点集合和边集合分别为:V(G1)={1,2,3,4,5,6,7},

E(G1)={(1,2),(l,3),(2,3),(3,4),(3,5),(5,6),(5,7)}。

 图(c)为有向图,其中G3的顶点集合和弧集合分别为

V(G3)={1,2,3,4,5,6},

E(G3)={<1,2>,<1,3>,<1,4>,<3,1>,<4,5>,<5,6>,<6,4>} 

2  图的存储结构 

2.1 邻接矩阵

邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设G=(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵。

无向图的邻接矩阵是以主对角线对称的,有向图的邻接矩阵可能是不对称的。 在有向图中: 第 i 行 1 的个数就是顶点 i 的出度,第 j 列 1 的个数就是顶点 j 的入度。 在无向图中, 第 i 行 (列) 1 的个数就是顶点i 的度。

无向图的邻接矩阵


有向图的邻接矩阵


无向图及其邻接矩阵 


有向图及其邻接矩阵 


2.2 邻接表 (图的链式存储结构)


在有向图的邻接表中,第 i 个链表中结点的个数是顶点Vi的出度。在有向图的逆邻接表中,第 i 个链表中结点的个数是顶点Vi 的入度。

3  拓扑排序 

通常我们把计划、施工过程、生产流程、程序流程等都当成一个工程,一个大的工程常常被划分成许多较小的子工程,这些子工程称为活动。这些活动完成时,整个工程也就完成了。 

例如,计算机专业学生的课程开设可看成是一个工程,每一门课程就是工程中的活动,下图给出了若干门所开设的课程,其中有些课程的开设有先后关系,有些则没有先后关系,有先后关系的课程必须按先后关系开设,如开设数据结构课程之前必

须先学完程序设计基础及离散数学,而开设离散数学则必须先并行学完高等数学、程序设计基础课程。

我们用一种有向图来表示课程开设,在这种有向图中,顶点表示活动,有向边表示活动的优先关系,这种有向图叫做顶点表示活动的网络(Actire On

 Vertices)简称为AOV网。

进行拓扑排序的方法:

输入AOV网络。令 n 为顶点个数。在AOV网络中选一个没有直接 前驱的顶点,  并输出之; 从图中删去该顶点, 同时删去所有它发出的有向边;重复以上 、 步, 直到全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;或

图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。

拓扑排序的过程:



最后得到的拓扑有序序列为 C4 , C0 , C3 , C2 , C1 , C5 。它满足图中给出的所有前驱和后继关系,对于本来没有这种关系的顶点,如C4和C2,也排出了先后次序关系。

在实现拓扑排序的算法中,采用邻接表作为有向图的存储结构,每个顶点设置一个单链表,每个单链表有一个表头结点,在表头结点中增加一个存放顶点入度的域count,这些表头结点构成一个数组,表头结点定义如下:

typedef struct             //表头结点{ Vertex data;             //顶点信息  int count;               //存放顶点入度  ArcNode *firstarc;       //指向第一条弧}Vnode;

在执行拓扑排序的过程中,当某个顶点的入度为零(没有前驱顶点)时,就将此顶点输出,同时将该顶点的所有后继顶点的入度减1,相当于删除所有以该顶点为尾的弧。为了避免重复检测顶点的入度是否为零,需要设立一个栈来存放入度为零的顶

点。执行拓扑排序的算法如下: 

void topsort(VNode adj[],int n){  int i,j;   int stack[MAXV],top=0;    //栈stack的指针为top   ArcNode *p;   for(i=0;i<n;i++)     if(adj[i].count==0)     {  top++;    stack[top]=i;     }   while(top>0)  //栈不为空   { i=stack[top];       top--;                                 //顶点vi出栈     printf(“%d”,i);                 //输出vi     p=adj[i].firstarc;              //指向以vi为弧尾的第一条弧while(p!=NULL)   {   j=p->adjvex;                  //以vi为弧尾的弧的另一顶点vj       adj[j].count--;                //顶点vj的入度减1       if(adj[j].count==0)         //入度为0的相邻顶点入栈        { top++;     stack[top]=j;        }       p=p->nextarc;               //指向以vi为弧尾的下一条弧     }   } } 

对于有n个顶点和e条边的有向图而言,for循环中建立入度为0的顶点栈时间为O(n);若在拓扑排序过程中不出现有向环,则每个顶点出栈、入栈和入度减1的操作在while(top>0)循环语句中均执行e次,因此拓扑排序总的时间花费为O (n+e)。 


1 0
原创粉丝点击