标签:拓扑排序
集合: 数据元素间的关系是同属一个集合。
线性结构:结点间的关系是线性关系,除开始结点和终端结点外,每个结点只有一个直接前趋和直接后继。
树形结构:结点间的关系实质上是层次关系,同层上的每个结点可以和下一层的零个或多个结点(即孩子)相关,但只能和上一层的一个结点(即双亲)相关(根结点除外)。
图(Graph)结构:对结点(图中常称为顶点)的前趋和后继个数不加限制的,即结点之间的关系是任意的。 图是一种较线性表和树更为复杂的非线性结构。是对结点的前趋和
后继个数不加限制的数据结构,用来描述元素之间“多对多”的关系。
图是由一个顶点集 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>}
邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设G=(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵。
无向图的邻接矩阵是以主对角线对称的,有向图的邻接矩阵可能是不对称的。 在有向图中: 第 i 行 1 的个数就是顶点 i 的出度,第 j 列 1 的个数就是顶点 j 的入度。 在无向图中, 第 i 行 (列) 1 的个数就是顶点i 的度。
无向图的邻接矩阵
有向图的邻接矩阵
无向图及其邻接矩阵
有向图及其邻接矩阵
在有向图的邻接表中,第 i 个链表中结点的个数是顶点Vi的出度。在有向图的逆邻接表中,第 i 个链表中结点的个数是顶点Vi 的入度。
通常我们把计划、施工过程、生产流程、程序流程等都当成一个工程,一个大的工程常常被划分成许多较小的子工程,这些子工程称为活动。这些活动完成时,整个工程也就完成了。
例如,计算机专业学生的课程开设可看成是一个工程,每一门课程就是工程中的活动,下图给出了若干门所开设的课程,其中有些课程的开设有先后关系,有些则没有先后关系,有先后关系的课程必须按先后关系开设,如开设数据结构课程之前必
须先学完程序设计基础及离散数学,而开设离散数学则必须先并行学完高等数学、程序设计基础课程。
我们用一种有向图来表示课程开设,在这种有向图中,顶点表示活动,有向边表示活动的优先关系,这种有向图叫做顶点表示活动的网络(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)。
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:拓扑排序
原文地址:http://blog.csdn.net/u011479875/article/details/47284629