数据结构 第六章 图

6.1 图的逻辑结构

6.1.1 图的定义和基本术语

在图中常将数据元素称为顶点。

图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:

                           G=(VE)

其中:G表示一个图,V是图G中顶点的集合,E是图G中顶点之间边的集合

在图中,顶点个数不能为零,但可以没有边。

若顶点vivj之间的边没有方向,则称这条边为无向边,表示为(vi,vj)

如果图的任意两个顶点之间的边都是无向边,则称该图为无向图。

若从顶点vivj的边有方向,则称这条边为有向边,表示为<vi,vj>

如果图的任意两个顶点之间的边都是有向边,则称该图为有向图。

简单图:在图中,若不存在顶点到其自身的边,且同一条边不重复出现。

邻接、依附

无向图中,对于任意两个顶点vi和顶点vj,若存在边(vivj),则称顶点vi和顶点vj互为邻接点,同时称边(vivj)依附于顶点vi和顶点vj

有向图中,对于任意两个顶点vi和顶点vj,若存在弧<vivj>,则称顶点vi邻接到顶点vj,顶点vj邻接自顶点vi,同时称弧<vivj>依附于顶点vi和顶点vj

无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。

有向完全图:在有向图中,如果任意两个顶点之间都存在方向相反的两条弧,则称该图为有向完全图。 

含有n个顶点的无向完全图有n×(n-1)/2条边。

含有n个顶点的有向完全图有n×(n-1)条边。

稀疏图:称边数很少的图为稀疏图;

稠密图:称边数很多的图为稠密图。

顶点的度:在无向图中,顶点v的度是指依附于该顶点的边数,通常记为TD (v)

顶点的入度:在有向图中,顶点v的入度是指以该顶点为弧头的弧的数目,记为ID (v)

顶点的出度:在有向图中,顶点v的出度是指以该顶点为弧尾的弧的数目,记为OD (v)

权:是指对边赋予的有意义的数值量。

网:边上带权的图,也称网图。

路径:在无向图G=(V, E)中,从顶点vp到顶点vq之间的路径是一个顶点序列(vp=vi0,vi1,vi2, …, vim=vq),其中,(vij-1,vij)E1jm)。若G是有向图,则路径也是有方向的,顶点序列满足<vij-1,vij>E

回路(环):第一个顶点和最后一个顶点相同的路径。

简单路径:序列中顶点不重复出现的路径。

简单回路(简单环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路。

子图:若图G=VE),G'=V'E'),如果V'ÍV E' Í E ,则称图G'G的子图。

连通图:在无向图中,如果从一个顶点vi到另一个顶点vj(ij)有路径,则称顶点vivj是连通的。如果图中任意两个顶点都是连通的,则称该图是连通图。

连通分量:非连通图的极大连通子图称为连通分量

极大连通子图:

1.含有极大顶点数;

2. 依附于这些顶点的所有边。

强连通图:在有向图中,对图中任意一对顶点vivj (ij),若从顶点vi到顶点vj和从顶点vj到顶点vi均有路径,则称该有向图是强连通图。

强连通分量:非强连通图的极大强连通子图

生成树:n个顶点的连通图G的生成树是包含G中全部顶点的一个极小连通子图。

生成森林:在非连通图中,由每个连通分量都可以得到一棵生成树,这些连通分量的生成树就组成了一个非连通图的生成森林。

6.1.2 图的抽象数据类型定义

ADT Graph

Data

   顶点的有穷非空集合和边的集合

Operation

InitGraph

    前置条件:图不存在

    输入:无

    功能:图的初始化

    输出:无

    后置条件:构造一个空的图

DestroyGraph

    前置条件:图已存在

    输入:无

    功能:销毁图

    输出:无

    后置条件:释放图所占用的存储空间

DFSTraverse

    前置条件:图已存在

    输入:遍历的起始顶点v

    功能:从顶点v出发深度优先遍历图

    输出:图中顶点的一个线性排列

    后置条件:图保持不变

 BFSTraverse

    前置条件:图已存在

    输入:遍历的起始顶点v

    功能:从顶点v出发广度优先遍历图

    输出:图中顶点的一个线性排列

    后置条件:图保持不变

endADT

6.1.3图的遍历操作

1. 深度优先遍历

基本思想:

⑴访问顶点v

⑵从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;

⑶重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

伪代码:

1. 访问顶点v; visited[v] = 1;

2. w =顶点v的第一个邻接点;

3. while (w存在)

   3.1 if (w未被访问) 从顶点w出发递归执行该算法;

   3.2 w = 顶点v的下一个邻接点;

2. 广度优先遍历

基本思想:

⑴访问顶点v

⑵依次访问v的各个未被访问的邻接点v1, v2, …, vk

⑶分别从v1v2vk出发依次访问它们未被访问的邻接点,并使先被访问顶点的邻接点先于后被访问顶点的邻接点被访问。直至图中所有与顶点v有路径相通的顶点都被访问到。

伪代码:

1. 初始化队列Q;

2. 访问顶点v; visited [v]=1; 顶点v入队列Q;

3. while (队列Q非空)

    3.1 v=队列Q的队头元素出队;

   3.2 w=顶点v的第一个邻接点;

   3.3 while (w存在)

         3.3.1 如果w 未被访问,则

                   访问顶点w; visited[w]=1; 顶点w入队列Q

         3.3.2 w=顶点v的下一个邻接点;

6.2 图的存储结构及实现

6.2.1 邻接矩阵

基本思想:用一个一维数组存储图中顶点的信息,用一个二维数组(称为邻接矩阵)存储图中各顶点之间的邻接关系。

构造函数:

1.       确定图的顶点个数和边的个数;

2. 输入顶点信息存储在一维数组vertex中;

3. 初始化邻接矩阵;

4. 依次输入每条边存储在邻接矩阵arc中;

    4.1 输入边依附的两个顶点的序号i, j

    4.2 将邻接矩阵的第i行第j列的元素值置为1

    4.3 将邻接矩阵的第j行第i列的元素值置为1

template <class DataType>

MGraph<DataType> ::MGraph(DataType a[ ], int n, int e)

{

   vertexNum = n; arcNum = e;

   for (i = 0; i < vertexNum; i++)

       vertex[i] = a[i];

   for (i = 0; i < vertexNum; i++)          //初始化邻接矩阵

       for (j = 0; j < vertexNum; j++)

            arc[i][j] = 0;            

   for (k = 0; k < arcNum; k++)          //依次输入每一条边

   {

       cin >> i >> j;                      //输入边依附的两个顶点的编号

       arc[i][j] = 1; arc[j][i] = 1;            //置有边标志

   }

}

深度优先遍历:

template <class DataType>

void MGraph<DataType> ::DFSTraverse(int v) 

{

   cout << vertex[v]; visited[v] = 1;

   for (j = 0; j < vertexNum; j++)

       if (arc[v][j] == 1 && visited[j] == 0) DFSTraverse( j );

}

 广度优先遍历:

template <class DataType>

void MGraph<DataType> ::BFSTraverse(int v)

{

   front = rear = -1;   //初始化顺序队列

   cout << vertex[v]; visited[v] = 1; Q[++rear] = v;

   while (front != rear)                  //当队列非空时

   {

        v = Q[++front];                  //将队头元素出队并送到v

       for (j = 0; j < vertexNum; j++)

            if (arc[v][j] == 1 &&visited[j] == 0 ) {

                 cout << vertex[j]; visited[j] = 1;Q[++rear] = j;

            }

   }

}

6.2.2 邻接表

邻接表存储的基本思想:对于图的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,称为顶点vi的边表(对于有向图则称为出边表),所有边表的头指针和存储顶点信息的一维数组构成了顶点表。

6.3 最小生成树

生成树的代价:设G = (V, E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价。

最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树。 

假设G=(V, E)是一个无向连通网,U是顶点集V的一个非空子集。若(u, v)是一条具有最小权值的边,其中uUvVU,则必存在一棵包含边(u, v)的最小生成树。

基本思想:设G=(V, E)是具有n个顶点的连通网,T=(U, TE)G的最小生成树, T的初始状态为U={u0}u0V),TE={ },重复执行下述操作:在所有uUvV-U的边中找一条代价最小的边(u, v)并入集合TE,同时v并入U,直至U=V

Prim算法的基本思想用伪代码描述如下:

1. 初始化两个辅助数组lowcostadjvex

2. 输出顶点u0,将顶点u0加入集合U中;

3. 重复执行下列操作n-1

  3.1 lowcost中选取最短边,取adjvex中对应的顶点序号k

  3.2 输出顶点k和对应的权值;

  3.3 将顶点k加入集合U中;

  3.4 调整数组lowcostadjvex

克鲁斯卡尔(Kruskal)算法

基本思想:设无向连通网为G(V, E),令G的最小生成树为T(U, TE),其初态为UVTE{ },然后,按照边的权值由小到大的顺序,考察G的边集E中的各条边。若被考察的边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T中的连通分量个数为1时,此连通分量便为G的一棵最小生成树。

伪代码:

1. 初始化辅助数组parent[n]num = 0

2. 依次考查每一条边for (i = 0; i < arcNum; i++)

   2.1 vex1 = edge[i].from所在生成树的根结点;

   2.2 vex2 = edge[i].to所在生成树的根结点;

   2.3 如果vex1 != vex2,执行下述操作:

         2.3.1 parent[vex2] = vex1;

         2.3.2 num++;

         2.3.3 if (num == n-1) 算法结束;

6.4 最短路径

在非网图中,最短路径是指两顶点之间经历的边数最少的路径。

在网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径。

Dijkstra算法

基本思想:设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,对viV-S,假设从源点vvi的有向边为最短路径。以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。重复上述过程,直到集合V中全部顶点加入到集合S中。

伪代码:

1. 初始化数组distpaths

2. while (s中的元素个数<n)

    2.1 dist[n]中求最小值,其下标为k

    2.2 输出dist[j]path[j]

    2.3 修改数组distpath

    2.4 将顶点vk添加到数组s中;

Floyd算法

基本思想:对于从vivj的弧,进行n次试探:首先考虑路径vi,v0,vj是否存在,如果存在,则比较vi,vjvi,v0,vj的路径长度,取较短者为从vivj的中间顶点的序号不大于0的最短路径。在路径上再增加一个顶点v1,依此类推,在经过n次比较后,最后求得的必是从顶点vi到顶点vj的最短路径。  

6.5 有向无环图及其应用

6.5.1 AOV网与拓扑排序

AOV网:在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,称这样的有向图为顶点表示活动的网,简称AOV网。

AOV网特点:

1.AOV网中的弧表示活动之间存在的某种制约关系。

2.AOV网中不能出现回路。

拓扑序列:设G=(VE)是一个具有n个顶点的有向图,V中的顶点序列v1, v2, …, vn称为一个拓扑序列,当且仅当满足下列条件:若从顶点vivj有一条路径,则在顶点序列中顶点vi必在顶点vj之前。

拓扑排序:对一个有向图构造拓扑序列的过程称为拓扑排序。

基本思想:

⑴从AOV网中选择一个没有前驱的顶点并且输出;

⑵从AOV网中删去该顶点,并且删去所有以该顶点为尾的弧;

⑶重复上述两步,直到全部顶点都被输出,或AOV网中不存在没有前驱的顶点。

伪代码:

1. S初始化;累加器count初始化;

2. 扫描顶点表,将没有前驱的顶点压栈;

3. 当栈S非空时循环

       3.1 vj=退出栈顶元素;输出vj;累加器加1

       3.2 将顶点vj的各个邻接点的入度减1

       3.3 将新的入度为0的顶点入栈;

4. if (count<vertexNum) 输出有回路信息;

6.5.2 AOE网与关键路径

AOE网:在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,边上的权值表示活动的持续时间,称这样的有向图叫做边表示活动的网,简称AOE网。AOE网中没有入边的顶点称为始点(或源点),没有出边的顶点称为终点(或汇点)。

AOE网的性质:

⑴只有在某顶点所代表的事件发生后,从该顶点出发的各活动才能开始;

⑵只有在进入某顶点的各活动都结束,该顶点所代表的事件才能发生。

关键路径:在AOE网中,从始点到终点具有最大路径长度(该路径上的各个活动所持续的时间之和)的路径称为关键路径。

关键活动:关键路径上的活动称为关键活动。

关键路径可能不只一条,重要的是找到关键活动

要找出关键路径,必须找出关键活动, 即不按期完成就会影响整个工程完成的活动。

首先计算以下与关键活动有关的量:

⑴事件的最早发生时间ve[k]

⑵事件的最迟发生时间vl[k]

⑶活动的最早开始时间e[i]

⑷活动的最晚开始时间l[i]

最后计算各个活动的时间余量 l[k] - e[k],时间余量为0者即为关键活动。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值