slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
第六章 图 第一节 图的基本概念和基本操作 第二节 图的存储表示 第三节 图的遍历 ç¬ PowerPoint Presentation
Download Presentation
第六章 图 第一节 图的基本概念和基本操作 第二节 图的存储表示 第三节 图的遍历 ç¬

Loading in 2 Seconds...

play fullscreen
1 / 79

第六章 图 第一节 图的基本概念和基本操作 第二节 图的存储表示 第三节 图的遍历 ç¬ - PowerPoint PPT Presentation


  • 132 Views
  • Uploaded on

第六章 图 第一节 图的基本概念和基本操作 第二节 图的存储表示 第三节 图的遍历 第四节 最小生成树 第五节 最短路径 第六节 拓扑排序 本 章 小 结 实 训 思 考 与 习 题. 学习要求: 掌握图的基本概念和术语、图的存储结构、图的深度优先和广度优先搜索算法以及图的应用。 主要内容: 图是一种复杂的非线性数据结构。本章介绍了图的基本概念和术语、图的存储结构、图的深度优先和广度优先搜索算法、最小生成树的概念及构造算法和最短路径的概念。. 第六章 图.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about '第六章 图 第一节 图的基本概念和基本操作 第二节 图的存储表示 第三节 图的遍历 ç¬' - jason


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide1
第六章 图

第一节 图的基本概念和基本操作

第二节 图的存储表示

第三节 图的遍历

第四节 最小生成树

第五节 最短路径

第六节 拓扑排序

本 章 小 结

实 训

思 考 与 习 题

slide2

学习要求:

掌握图的基本概念和术语、图的存储结构、图的深度优先和广度优先搜索算法以及图的应用。

主要内容:

图是一种复杂的非线性数据结构。本章介绍了图的基本概念和术语、图的存储结构、图的深度优先和广度优先搜索算法、最小生成树的概念及构造算法和最短路径的概念。

第六章 图

slide3
图是一种比线性表和树更加复杂的数据结构。在线性表中,数据元素之间呈现一种线性关系,即每个元素只有一个直接前驱和一个直接后继;在树结构中,结点之间是一种层次关系,即每个结点只有一个直接前驱,但可有多个直接后继;而在图结构中,每个结点既可以有多个直接前驱,也可以有多个直接后继。前面讨论的线性表和树都可以看成是两种特殊的图。图是一种比线性表和树更加复杂的数据结构。在线性表中,数据元素之间呈现一种线性关系,即每个元素只有一个直接前驱和一个直接后继;在树结构中,结点之间是一种层次关系,即每个结点只有一个直接前驱,但可有多个直接后继;而在图结构中,每个结点既可以有多个直接前驱,也可以有多个直接后继。前面讨论的线性表和树都可以看成是两种特殊的图。

图结构可以描述各种复杂的数据对象,因此图的应用极为广泛,已渗透到诸如语言学、逻辑学、物理、化学、电讯工程、计算机科学以及数学的其他分支中。

本章首先介绍图的概念,然而讨论图在计算机中的表示方法以及有关图的几个典型应用。

slide4
第一节 图的基本概念和基本操作

一、图的定义和术语

(一)图的定义

图G(graph)是由两个集合V和E组成,记为G=(V,E)。其中,G表示一个图,V是顶点的有穷非空集合,E是V中顶点偶对(称为边)的有穷集合。通常,也将图G的顶点集和边集分别记为V(G)和E(G),E(G)可以是空集。若E(G)为空,则图G只有顶点而没有边。图6.1给出了一个图的示例,在该图中:

集合V={ v1,v2,v3,v4,v5};

集合E={ (v1,v2),( v1,v4),

(v2,v3),(v2,v5),(v3,v4),(v3,v5)};

图6.1 无向图G1

slide5
(二)图的相关术语

1. 无向图

在图G中,如果每条边都是没有方向的,则称G为无向图,无向图中的边均是顶点的无序偶对,无序偶对通常用圆括号表示,即用(vi,vj)表示顶点vi和vj间相连的边。在无向图中,(vi,vj)和(vj,vi)表示同一条边。如图6.1所示,图G1是一个无向图。

2. 有向图

在图G中,如果每条边都是有方向的,则称G为有向图,有向图中的边均是顶点的有序偶对,有序偶对通常用尖括号表示,即用<vi,vj>表示从顶点vi到顶点vj的一条有向边。因此<vi,vj>和<vj,vi>表示不同的两条有向边。如图6.2所示,图G2是一个有向图。

slide6

图6.2 有向图G2

3. 顶点、边、弧、弧头和弧尾

数据元素vi称为顶点,P(vi,vj)表示在顶点vi和顶点vj之间有一条直接连线。如果是在无向图中,则称这条连线为边;如果是在有向图中,一般称这条连线为弧。边用顶点的无序偶对(vi,vj)来表示,称顶点vi和顶点vj互为邻接点,边(vi,vj)依附或关联于顶点vi与顶点vj。弧用顶点的有序偶对<vi,vj>来表示,有序偶对的第一个顶点vi被称为始点(或弧尾),在图中就是不带箭头的一端;有序偶对的第二个顶点vj被称为终点(或弧头),在图中就是带箭头的一端。

slide7
4. 无向完全图

在一个无向图中,如果任意两顶点之间都有一条边相连接,则称该图为无向完全图。可以证明,在一个含有n个顶点的无向完全图中,有n(n-1)/2条边。

5. 有向完全图

在一个有向图中,如果任意两顶点之间都有方向互为相反的两条弧相连接,则称该图为有向完全图。在一个含有n个顶点的有向完全图中,有n(n-1)条弧。

6. 稠密图、稀疏图

含有很多条边或弧的接近完全图的图,称为稠密图;反之,含有很少边或弧的图称为稀疏图。

7. 顶点的度、入度和出度

顶点的度(degree)是指依附于某顶点v的边或弧的条数,通常记为D(v)。在有向图中,要区分顶点的入度和出度的概念。顶点v的入度是指以顶点v为终点的弧的数目,记为ID(v);顶点v的出度是指以顶点v为始点的弧的数目,记为OD(v),有D(v)= ID(v)+ OD(v)。

slide8
在图6.1所示的无向图中,顶点v1的度为2,顶点v2的度为3;在图6.2所示的有向图中,顶点v1的度为3,其中,入度为1,出度为2。在图6.1所示的无向图中,顶点v1的度为2,顶点v2的度为3;在图6.2所示的有向图中,顶点v1的度为3,其中,入度为1,出度为2。

无论是有向图还是无向图,顶点数n、边数e和度数之间有如下关系:

8. 边的权、网络

图中每条边都可以附有一个对应的数值,这种与边有关的数值称为权(weight)。权可以表示从一个顶点到另一个顶点的距离或花费的代价。边上带权的图称为带权图,也称为网络(network),图6.3所示的是网络G3。

图6.3 网络G3

slide9
9. 路径、路径长度

在无向图G中,顶点vp到顶点vq之间的路径(path)是指顶点序列vp,vi1,vi2,…,vim,vq。其中,(vp,vi1), (vi1,vi2), …,(vim,vq)分别为图中的边。若G是有向图,则路径也是有向的,它由有向边<vp,vi1>,<vi1,vi2>,…,<vim,vq>组成。路径上边或弧的数目称为路径长度。

图6.1所示的无向图中,v1→v4,v1→v2→v3→v4和v1→v2→v5→v3→v4是从顶点v1到v4的三条路径,路径的长度分别为1,3和4。

10. 回路、简单路径和简单回路

第一个顶点和最后一个顶点相同的路径称为回路或环(cycle)。序列中顶点不重复出现的路径称为简单路径。除第一个顶点与最后一个顶点之外,其他顶点不重复出现的回路称为简单回路。

11. 子图

对于图G=(V,E),G′=(V′,E′),若存在V′是V的子集,E′是E的子集,则称图G′是图G的一个子图。

图6.4(a)和图6.4(b)所示是图6.1的两个子图。

slide10
12. 连通的、连通图和连通分量

在无向图中,如果从一个顶点vi到另一个顶点vj(i≠j)有路径,则称顶点vi和vj是连通的。如果图中任意两顶点都是连通的,则称该图为连通图。无向图的极大连通子图称为连通分量。

图6.4 无向图G1的两个子图

slide11
图6.1是一个连通图,图6.5(a)是非连通图。图6.5(a)有两个连通分量,如图6.5(b)所示。图6.1是一个连通图,图6.5(a)是非连通图。图6.5(a)有两个连通分量,如图6.5(b)所示。

图6.5 无向图及连通分量

13. 强连通图和强连通分量

对于有向图来说,若图中任意一对顶点vi和vj(i≠j)均有从一个顶点vi到另一个顶点vj的路径,也有从vj到vi的路径,则称该有向图是强连通图。有向图的极大强连通子图称为强连通分量。

slide12
图6.2中有两个强连通分量,如图6.6所示。

14. 生成树

所谓连通图G的生成树,是G的包含其全部n个顶点的一个极小连通子图。它必定包含且仅包含G的n-1条边。在生成树中添加任意一条原图中的边必定会产生回路,因为新添加的边使其所依附的两个顶点之间有了第二条路径。若生成树中减少任意一条边,则必然成为非连通的。

图6.6 图6.2的强连通分量

slide13

图6.7所示为图6.1的一棵生成树。

15. 生成森林

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

图6.5(b)所示为非连通图的连通分量构成的生成森林。

图6.7 一棵生成树

slide14

二、图的基本操作

图的基本操作有:

1CreatGraph(G):输入图G的顶点和边,建立图G的存储。

2DestroyGraph(G):释放图G占用的存储空间。

3GetVex(G,v):在图G中找到顶点v,并返回顶点v的相关信息。

4PutVex(G,v,value):在图G中找到顶点v,并将value值赋给顶点v。

5InsertVex(G,v):在图G中增添新顶点v。

6DeleteVex(G,v):在图G中,删除顶点v以及所有和顶点v相关联的边或弧。

7InsertArc(G,v,w):在图G中增添一条从顶点v到顶点w的边或弧。

8DeleteArc(G,v,w):在图G中删除一条从顶点v到顶点w的边或弧。

9DFSTraverse(G,v):在图G中,从顶点v出发深度优先遍历图G。

10BFSTraverse(G,v):在图G中,从顶点v出发广度优先遍历图G。

slide15
第二节 图的存储表示

由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此很难用顺序存储结构来存放图。如果用多重链表表示图,即由一个数据域和多个指针域组成的结点来表示图中的一个顶点,顶点之间的边或弧用指针关联起来,这是一种最简单的链式存储结构,但由于图中各顶点的度各不相同,这样结点的指针域不定长,会给算法设计带来很大的困难。在实际应用中,是根据具体的图和所定义的操作来设计适当的存储结构或表示方法的。下面介绍两种常用的存储方法:邻接矩阵表示法和邻接表表示法。

为了适合用C语言描述,从本节起假定顶点序号从0开始,即图G的顶点集的一般形式是V(G)={ v0 ,v1,v2,…,vn-1 }。

一、邻接矩阵

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

slide16
若图G是网络,则邻接矩阵可定义为:

其中,wij表示边(vi,vj)或弧<vi,vj>上的权值;∞表示一个计算机允许的、大于所有边上权值的正整数。

图6.8(a)无向图的邻接矩阵表示如图6.8(b)所示。

图6.9(a)有向图的邻接矩阵表示如图6.9(b)所示。

slide17
图6.9 有向图及其邻接矩阵

图6.8 无向图及其邻接矩阵

slide18
图6.3所示网络的邻接矩阵表示如图6.10所示。

图6.10 邻接矩阵表示法

从图的邻接矩阵存储方法容易看出这种表示具有以下特点:

1无向图的邻接矩阵一定是一个对称矩阵。因此,在具体存放邻接矩阵时只需存放上(或下)三角矩阵的元素即可。

2对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的度TD(vi)。

3对于有向图,邻接矩阵的第i行非零元素(或非∞元素)的个数正好是第i个顶点的出度OD(vi)。

4对于有向图,邻接矩阵的第i列非零元素(或非∞元素)的个数正好是第i个顶点的入度ID(vi)。

slide19
5用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连。但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,这时所花费的时间代价很大。这是用邻接矩阵存储图的局限性。5用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连。但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,这时所花费的时间代价很大。这是用邻接矩阵存储图的局限性。

采用邻接矩阵表示法存储图时,除了使用一个一维数组来存储顶点信息,用一个二维数组存储顶点之间的边或弧,还需要明确指出图的顶点数和边(或弧)数以及图的类型。对应的结构说明如下:

#define VEXTYPE int ∥顶点类型

#define ADJTYPE int ∥边的数值类型

#define MAXLEN 40 ∥最大顶点数

typedef struct

{ VEXTYPE vexs[MAXLEN]; ∥图中顶点的信息

ADJTYPE arcs[MAXLEN][MAXLEN] ∥邻接矩阵

int vexnum, arcnum; ∥顶点数和边数

} MGRAPH;

slide20
图的类型分四种:有向图,kind=1;无向图,kind=2;有向网,kind=3;无向网,kind=4。图的类型分四种:有向图,kind=1;无向图,kind=2;有向网,kind=3;无向网,kind=4。

【算法6.1】 建立一个有向网的邻接矩阵存储的算法。

#define MAX 10000∥设∞为MAX

MGRAPH create_mgraph()

{ inti, j, k, h;

char b, t;

MGRAPH mg;

mg.kind=3;

printf ("请输入顶点数和边数:");

scanf("%d%d", &i, &j);

mg.vexnum=i;

mg.arcnum=j;

for (i=0; i<mg.vexnum; i++)

{ printf("第%d个顶点信息:",i+1);

scanf("%d", &mg.vexs[i]);}

for (i=0; i<mg.vexnum; i++)

slide21
for (j=0; j<mg.vexnum; j++)

mg.arcs[i][j]=MAX;

for (k=1; k<=mg.arcnum; k++)

{ printf("第%d条边的起始顶点编号和终止顶点编号:\n", k);

scanf("%d%d", &i, &j);

while (i<1‖i>mg.vexnum‖j<1‖j>mg.vexnum)

{ printf("编号超出范围,重新输入:");

scanf("%d%d", &i, &j);

}

printf("此边的权值:");

scanf("%d", &h);

mg.arcs[i-1][j-1]=h;

}

return mg;

}

slide22
二、邻接表

邻接表表示法类似于树的孩子链表表示法,是图的一种链式存储结构。在邻接表中,对于图G中的每个顶点vi,把所有邻接于vi的顶点vj链成一个单链表,这个单链表被称为顶点vi的邻接表。邻接表中每个表结点均有两个域,一是邻接点域adjvex,用以存放与vi相邻接的顶点vj的序号j;二是链域next,用来将邻接表的所有表结点链在一起,如图6.11(a)所示。再为每个顶点vi的邻接表设置一个头结点,头结点包含两个域:一是顶点域vertex,用来存放顶点vi的名或其他有关信息;二是指针域firstedge,它是vi的邻接表的头指针,如图6.11(b)所示。如果用邻接表表示网,则还需要在结点中增加一个存放权值的域(weighth)。如图6.11(c)所示。

对于无向图而言,vi的邻接表中每个表结点都对应于与vi相关联的一条边;对于有向图来说,vi的邻接表中每个表结点都对应于以vi为始点射出的一条弧。因此,我们将无向图的邻接表称为边表,将有向图的邻接表称为出边表,将邻接表的表头向量称为顶点表。

slide26

有向图还有一种称为逆邻接表表示法,该方法为图中每个顶点vi建立一个入边表,入边表中的每个表结点均对应一条以vi为终点(即射入vi)的边。有向图还有一种称为逆邻接表表示法,该方法为图中每个顶点vi建立一个入边表,入边表中的每个表结点均对应一条以vi为终点(即射入vi)的边。

图6.9(a)所示的有向图,其逆邻接表表示如图6.14所示。

图6.14 有向图的逆邻接表

slide27

下面给出图的邻接表的结构说明:

#defineVEXTYPE int

#defineMAXLEN 40

typedef struct nodes ∥表结点结构

{ int adjvex; ∥存放与表头结点相邻接的顶点在数组中的序号

struct nodes *next; ∥指向与表头结点相邻的下一个顶点的表结点

}

EDGENODE

typedef struct

{ VEXTYPE vertex; ∥存放图中顶点的信息

slide28
EDGENODE *firstedge; ∥指针指向对应的单链表中的表结点

} VEXNODE;

typedef struct

{ VEXNODE adjlist[MAXLEN]; ∥邻接表表头向量

int vexnum, arcnum; ∥顶点数和边数

int kind; ∥图的类型

} ADJGRAPH

【算法6.2】 建立一个有向图邻接表的算法。

ADJGRAPH creat_adjgraph()

{

EDGENODE *p

int i, s, d;

ADJGRAPH adjg;

adjg.kind=1;

printf("请输入顶点数和边数:");

scanf("%d%d", &s, &d);

adjg.vexnum=s;

adjg.arcnum=d;

slide29
for (i=0; i<adjg.vexnum; i++)

{ printf("第%d个顶点信息:", i+1);

scanf("%d", &adjg.adjlist[i].vertex);

adjg.adjlist[i].firstedge=NULL; }

for (i=0; i<adjg.arcnum; i++)

{ printf("第%d条边的起始顶点编号和终止顶点编号:", i+1);

scanf("%d%d", &s, &d);

while (s<1‖s>adjg.vexnum‖d<1‖d>adjg.vexnum)

{ printf("编号超出范围,重新输入:");

scanf("%d%d", &s, &d); }

s--;

d--;

p=malloc(sizeof(EDGENODE));

p→adjvex=d;

p→next=adjg.adjlist[s].firstedge;

adjg.adjlist[s].firstedge=p; }

return adjg;

}

slide30
从算法中可以看到,与一个图对应的邻接表的存储结构可以不是唯一的。它主要反映在单链表中各结点的前后次序可以不同,并取决于建立邻接表的算法中结点是前插入还是后插入,以及各边的输入次序。从算法中可以看到,与一个图对应的邻接表的存储结构可以不是唯一的。它主要反映在单链表中各结点的前后次序可以不同,并取决于建立邻接表的算法中结点是前插入还是后插入,以及各边的输入次序。

从图的邻接表存储方法容易看出,图的邻接表表示法具有以下特点:

1若无向图G有n个顶点,e条边,则邻接表需n个表头结点和2e个表结点。显然,对于边很少的图,用邻接表比用邻接矩阵要节省存储空间。

2在无向图的邻接表中,顶点vi的度为第i个链表中表结点的个数。

3在有向图的邻接表中,一条弧对应一个表结点,表结点的数目和图中弧的数目相同。

4在有向图的邻接表中,求图中某个顶点vi的出度很容易,它就是第i个链表中的表结点的个数;若要求vi的入度,则必须扫描整个邻接表,为了方便求其入度,可以对有向图建立逆邻接表。

slide32
第三节 图的遍历

图的遍历是指从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次的过程。图的遍历是图的一种基本操作,是求解图的连通性问题、拓扑排序和求关键路径等算法的基础。

图的遍历通常有深度优先搜索和广度优先搜索两种方式,它们对无向图和有向图都适用。

slide33
一、深度优先搜索

图的深度优先搜索(depth first search)类似于树的先序遍历。假设给定图G的初态是所有顶点均未曾访问过,在G中任选一顶点v为初始出发点(源点),则深度优先搜索可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先搜索,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止;若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。

以图6.15为例,进行图的深度优先搜索。假设从顶点v1出发进行搜索,在访问了顶点v1之后,选择邻接点v2。因为v2未曾访问,则从v2出发进行搜索。依次类推,接着从v4、v8、v5出发进行搜索。在访问了v5之后,由于v5的邻接点都已被访问,则搜索回到v8。同样,搜索继续回到v4、 v2直到v1,此时由于v1的另一个邻接点v3未被访问,则搜索又从v1到v3,再由此继续进行下去,得到的顶点访问序列为: v1 → v2 → v4 →v8→ v5 →v3→v6→v7。过程示意图如图6.15(b)所示。

slide34
按深度优先搜索遍历规则还可以得到v1→v3→v7→v6→v2→v5→v8→v4等多种序列。按深度优先搜索遍历规则还可以得到v1→v3→v7→v6→v2→v5→v8→v4等多种序列。

因为深度优先搜索遍历是递归定义的,故容易写出其递归算法。

【算法6.3】 以邻接矩阵作为图的存储结构下的深度优先搜索遍历算法。

int visited[MAXLEN];

void dfs (ADJGRAPH adjg, int v)

∥从第v个顶点出发递归深度优先搜索遍历图G,G以邻接矩阵表示

{ int w;

visited[v]=1;

visitfunc(v);∥访问第v个顶点

for (w=firstadjvex(adjg, v); w; w=nextadjvex(adjg, v, w))

if (visited[w])

dfs(adjg, w); ∥对v的尚未访问的邻接顶点w递归调用dfs

}

slide35
【算法6.4】 以邻接表作为图的存储结构下的深度优先搜索遍历算法。

void dfs(ADJGRAPH adjg, int v)

{

EDGENODE *p;

int i;

visited[v-1]=1; ∥标记vi已访问

v--;

printf("%d", adjg.adjlist[v].vertex);

p=adjg.adjlist[v].firstedge; ∥取vi边表的头指针

while (pNULL) ∥依次搜索vi的邻接点vj

{ if (visited[p→adjvex]==0)∥若vj尚未被访问过,则以vj为出发纵深访问

dfs(adjg, (p→adjvex)+1);

p=p→next; } ∥找vi的下一个邻接点

}

slide36
二、广度优先搜索

广度优先搜索遍历(breadth first search)类似于树的层次遍历。设图G的初态是所有顶点均未访问过,在G中任选一顶点v为源点,则广度优先遍历可以定义为:首先访问出发点v,接着依次访问v的所有邻接点w1,w2,…,wt,然后再依次访问与w1,w2,…,wt邻接的所有未曾访问过的顶点,依此类推,直至图中所有和源点v有路径相通的顶点都已访问到为止,此时从v开始的搜索过程结束。若G是连通图,则遍历完成;否则,在图G中另选一个尚未访问的顶点作为新源点继续上述的搜索过程,直至G中所有顶点均已被访问为止。

以图6.15为例,进行广度优先搜索遍历,首先访问v1和v1的邻接点v2和v3,然后依次访问v2的邻接点v4和v5及v3的邻接点v6和v7,最后访问v4的邻接点v8。由于这些顶点的邻接点均已被访问,并且图中所有顶点都被访问,完成了图的遍历。得到的顶点访问序列为:

v1→ v2 → v3→ v4→ v5→ v6→ v7→ v8。过程示意图如图6.15(c)所示。

按广度优先搜索遍历规则还可以得到v1→ v3→ v2 → v6→ v7→ v4→ v5→ v8等多种序列。

slide37

图6.15 连通图深度优先搜索和广度优先搜索过程示意图

slide38
用邻接表作为存储结构,广度优先搜索遍历的算法设计如下:用邻接表作为存储结构,广度优先搜索遍历的算法设计如下:

【算法6.4】 以邻接表作为存储结构下的广度优先搜索遍历算法。

void bfs(ADJGRAPH adjg, int vi)

{ int visited[MAXLEN];

int i, v;

EDGENODE *p;

LINKQUEUE que, *q;

q=&que;

initlinkqueue(q);

for (i=0; i<adjg.vexnum; i++)

visited[i]=0;

visited[vi-1]=1;

printf("%4d", adjlist[vi-1].vertex);

enlinkqueue (q, vi);

while (emptylinkqueue (q))

{ v=dellinkqueue(q);

v--;

slide39
p=adjg.adjlist[v].firstedge;

while (pNULL)

{

if (visited[p→adjvex]==0)

{

visited[p→adjvex]=1;

printf("%d", adjg.adjlist [p→adjvex].vertex);

enlinkqueue(q,(p→adjvex)+1);

}

p=p→next;

}

}

slide40
第四节 最小生成树

前面已介绍过,对给定的连通图G,其极小连通子图是G的生成树。生成树中包含了连通图G中的所有的顶点和n-1条边。由于图的遍历序列不唯一,具有n个顶点的连通图G的生成树也就不一定是唯一的。

一、最小生成树的基本概念

如果无向连通图是一个网,那么,在它的所有生成树中,必有一棵树其边上的权值总和最小,我们称这棵生成树为最小生成树(也称最小代价生成树)。

最小生成树的概念可以应用到许多实际问题中。例如,有这样一个问题:构造一个造价最低的通信网络,把若干个城市联系在一起。在这若干个城市中,任意两个城市之间都可以建造通信线路,通信线路的造价依据城市间的距离的不同而不同。这时可以构造一个通信线路造价网络,在网络中,每个顶点表示一个城市,顶点之间的边表示城市之间可构造通信线路,每条边上的权值表示该条通信线路的造价,要想使总的造价最低,实际上就是寻找该网络的最小生成树。

slide41
构造最小生成树可以有多种算法,其中大多数构造算法都利用了最小生成树的性质(简称为MST性质):设G=(V,E)是一个连通网络,U是顶点集V的一个真子集。若(u,v)是G中所有的一个端点在U(u∈U)里、另一个端点不在U(即v∈V-U)里的边中,具有最小权值的一条边,则一定存在G的一棵最小生成树包括此边(u,v)。构造最小生成树可以有多种算法,其中大多数构造算法都利用了最小生成树的性质(简称为MST性质):设G=(V,E)是一个连通网络,U是顶点集V的一个真子集。若(u,v)是G中所有的一个端点在U(u∈U)里、另一个端点不在U(即v∈V-U)里的边中,具有最小权值的一条边,则一定存在G的一棵最小生成树包括此边(u,v)。

下面介绍两个利用MST性质构造最小生成的算法。

二、构造最小生成树的Prim算法

假设G=(V,E)为一连通网,其中V为网中所有顶点的集合,E为网中所有带权边的集合。设置两个新的集合U和T,其中集合U用于存放G的最小生成树中的顶点,集合T存放G的最小生成树中的边。令集合U的初值为U={u1}(假设构造最小生成树时,从顶点u1出发),集合T的初值为T={ }。

slide42
Prim算法的思想是:从所有u∈U、v∈V-U的边中,选取具有最小权值的边(u,v),将顶点v加入集合U中,将边(u,v)加入集合T中,如此不断重复,直到U=V时,最小生成树构造完毕。这时集合T中包含了最小生成树的所有边。

图6.16(a)所示的一个连通图,按照Prim算法思路,从顶点v1出发,该网的最小生成树的构造过程如图6.16(a)~(g)所示。

初始时,U={v1},V-U={v2,v3, v4, v5, v6, v7},T={ };在v1相关联的所有的边中,(v1, v2)的权值是最小的,因此取(v1, v2)为最小生成树的第一条边,如(b)所示,此时U={v1,v2},V-U={v3, v4,v5,v6,v7},T={( v1 v2)};在和v1、v2相关联的所有边中,(v2, v5)权值最小,取(v2, v5)为最小生成树的第二条边,如(c)所示;现U={v1,v2, v5},V-U={v3,v4, v6, v7},T={( v1,v2),(v2, v5)},在和v1、 v2、 v5相关联的所有边中,(v5, v4)的权值最小,取(v5, v4)为最小生成树的第三条边,如(d)所示,这样,U={v1, v2, v5, v4},V-U={v3, v6, v7},T={( v1, v2),( v2, v5),( v5, v4)};在所有和v1, v2, v5, v4相关联的边中,(v4, v6)为权

slide43
值最小的边,取(v4,v6)为最小生成树的第四条边,如(e)所示;这时U={v1,v2,v5,v4,v6},V-U={v3,v7},={(v1, v2),(v2, v5),(v5, v4),(v4, v6)};在所有和v1, v2, v5, v4, v6相关联的边中,(v4, v7)为权值最小的边,取(v4,v7)为权值最小的边,取(v4, v7)为最小生成树的第五条边,如(f)所示;这时U={v1, v2, v5, v4, v6,v7}, VU={v3};T={(v1, v2),(v2, v5),(v5, v4),(v4, v6),(v4, v7)};U中顶点和v3相关联的权值最小边为(v7, v3),取(v7, v3)为最小生成树的第六条边,如(g)所示;至此U=V。(g)即为最终得到的最小生成树。
slide44

(b)

(a)

(c)

(d)

slide45

(e)

(f)

(g)

图6.16 Prim算法构造最小生成树的过程

slide46
三、构造最小生成树的Kruskal算法

Kruskal算法是一种按照网中边的权值递增的顺序构造最小生成树的方法。其基本思想是:

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

此算法思想可简单描述如下:

T=(v, {});

while (T中所有边数e<n-1)

slide47
{

从E中选取当前最短边(u,v);

if (u,v)并入T之后不产生回路) 将边(u,v)并入T中;

从E中删去边(u,v);

}

对于图6.16(a)所示的网,按照Kruskal方法构造最小生成树的过程如图6.17所示。在构造过程中,按照网中边的权值由小到大的顺序,不断选取当前未被选取的边集中权值最小的边。

依据生成树的概念,n个结点的生成树,有n-1条边,故反复上述过程,直到选取了n-1条边为止,就构成了一棵最小生成树。

(a)

(b)

slide48

(d)

(c)

(e)

(f)

图6.17 Kruskal算法构造最小生成树的过程

slide49
第五节 最短路径

图的最短路径问题用途很广,例如,交通网络中常常提出这样的问题:从甲地到乙地之间是否有公路连通?在有多条通路的情况下,哪一条通路最短? 交通网络可用带权有向图来表示。顶点表示城市名称,边表示两个城市有路连通,边上权值可表示两城市之间的距离、交通费或途中所花费的时间等。如何使一个城市到另一个城市的运输时间最短或运费最省,就是一个求两座城市间最短路径的问题。

在带权有向图中A点(源点)到达B点(终点)的多条路径中,寻找一条各边权值之和最小的路径,即最短路径。求解图的最短路径问题主要包括两个方面:求图中某一顶点(源点)到其余各顶点的最短路径和求图中每一对顶点之间的最短路径。这两方面的问题可分别采用迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd)算法来实现。

注:最短路径与最小生成树不同,路径上不一定包含n个顶点。

slide50
一、从一个源点到其他各顶点的最短路径

给定一个带权有向图G=(V,E)与源点v,求从v到G中其他顶点的最短路径,并限定各边上的权值大于或等于0。

单源点最短路径是指:给定一个出发点(单源点)和一个有向网G=(V,E),求出源点到其他各顶点之间的最短路径。那么怎样求出单源点的最短路径呢?我们可以将源点到终点的所有路径都列出来,然后在里面选最短的一条即可。但是如果这样做,用手工方式可以,当路径特别多时,就显得特别麻烦,并且没有什么规律,因此不能用计算机算法来实现。

迪杰斯特拉(Dijkstra)在做了大量观察后,首先提出了一个按路径长度递增的次序产生各顶点的最短路径算法,我们称之为迪杰斯特拉算法。

(一)迪杰斯特拉算法的基本思想

迪杰斯特拉算法的基本思想是:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为顶点集合(用S表示),存放已求出其最短路径的顶点,第二组为尚未确定最短路径的顶点集合是

slide51
V-S(用U表示),其中V为网中所有顶点集合。按最短路径长度递增的次序逐个把U中的顶点加到S中,直到S中包含全部顶点,而U为空为止。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。V-S(用U表示),其中V为网中所有顶点集合。按最短路径长度递增的次序逐个把U中的顶点加到S中,直到S中包含全部顶点,而U为空为止。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

(二)迪杰斯特拉算法的具体步骤

1初始时,S只包含源点,S={v},v的距离为0。U包含除v外的其余顶点,U中顶点u的距离为边上的权(若v与u有边<v,u>)或∞(若u不是v的出边邻接点)。

2从U中选取一个距离v最小的顶点k,把k加入到S中(该选定的距离就是v到k的最短路径长度)。

3以k 作为新考虑的中间点,修改U中各顶点的距离:若从源点v到顶点u(u∈U)的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值为顶点k的距离加上边<k,u>上的权。

slide52
4重复步骤(2)、(3)直到所有顶点都包含在S中。4重复步骤(2)、(3)直到所有顶点都包含在S中。

例如,对图6.18所示的带权有向图,采用迪杰斯特拉算法求从顶点v0到其他顶点的最短路径时,S,U和从v0到各顶点的距离的变化如图6.19所示(S中加下划线者表示新加入的顶点,距离中加方框都表示修改后的距离值)。

求得结果为:

v0 →v1< v0, v1>4

v0 v2< v0, v1>,< v1, v2>5

v0 →v3< v0, v3>6

v0 →v5< v0, v1>,< v1, v2>,< v2,v5>9

v0 →v4< v0, v1>,< v1, v2>,< v2, v5>,<v5, v4>10

v0 →v6< v0, v1>,< v1, v2>,< v2, v5>,< v5, v4>,< v4, v6>16

则从v0到v1~ v6各顶点的最短距离分别为4,5,6,10,9和16。

slide53
S

{v0}

{v0,v1}

{v0, v1,v2}

{v0, v1,v2, v3}

{v0, v1,v2, v3, v5}

{v0, v1,v2, v3, v5, v4}

{v0, v1,v2, v3, v5, v4, v6 }

图6.19 迪杰斯特拉算法过程

图6.18 带权有向图

slide54

v0到v1~v6各顶点的距离

{4,6,6,∞,∞,∞ }

{4,5,6,11,∞,∞ }

{4,5,6,11,9,∞ }

{4,5,6,11,9,∞ }

{4,5,6,10,9,17 }

{4,5,6,10,9,16 }

{4,5,6,10,9,16 }

U

{v1,v2,v3,v4,v5, v6 }

{v2,v3,v4,v5,v6 }

{v3,v4,v5,v6 }

{v4,v5,v6 }

{v4,v6 }

{v6 }

{ }

图6.19 迪杰斯特拉算法过程

slide55
二、每一对顶点之间的最短路径

对于一个各边权值均大于零的有向图,对每一对顶点vi≠vj,求出vi与vj之间的最短路径和最短路径长度。

可以通过以每个顶点作为源点,执行Dijkstra算法,循环求出每对顶点之间的最短路径。除此之外,弗洛伊德算法也可用于求两顶点之间最短路径,其基本思想是:

如果vi到vj有弧,则从vi到vj存有一条长度为A[i][j]的路径,但该路径不一定是最短路径,需要进行几次试探。首先考虑路径(vi,v0, vj)是否存在(即判别弧< vi, v0>和<v0, vj>是否存在),如果存在,则比较(vi, vj)和(vi, v0, vj)的路径长度,取较短者为从vi到vj的中间顶点序号不大于0的最短路径。在路径上再增加一个顶点v1,若(vi,…, v1)和(v1,…, vj)是当前找到的中间顶点序号不大于0的最短路径,则(vi,…, v1,…, vj)就有可能是从vi到vj的中间顶点序号不大于0的最短路径,则(vi,…, v1,…, vj)就有可能是从vi到vj的中间顶点的序号不大于1的最短路径。将它和已经得到从vi到vj中间顶点序号不大于0的最短路径相比较,从中选出

slide56
长度较短者作为从vi到vj中间顶点序号不大于1的最短路径之后,再增加一个顶点v2,继续进行试探。依次类推。在一般情况下,若(vi,…,vk)和(vk,…, vj)分别是从vi到vk和vk到vj的中间顶点序号不大于k-1的最短路径,则将(vi,…, vk,…, vj)和已经得到的从vi到vj且中间顶点序号不大于k-1的最短路径相比较,取其长度较短者作为从vi到vj的中间顶点序号不大于k的最短路径。这样,经过几次比较后,最后求得的必然是从vi到vj的最短路径。按此方法,可同时求得每对顶点间的最短路径。

假设有向图G=(V,E)采用邻接矩阵cost存储,另外设置一个二维数组A用于存放当前顶点之间的最短路径长度,分量A[i][j]表示当前顶点vi到顶点vj的最短路径长度。弗洛伊德算法的基本思想是递推产生一个矩阵序列A0,A1,…,Ak,An,其中,Ak[i][j]表示从顶点vi到顶点vj的路径上所经过的顶点编号不大于k的最短路径长度。

slide57
第六节 拓扑排序

一个无环的有向图称作有向无环图(directed acycline graph),简称DAG图。有向无环图可以用来描述一项工程或任务的进行过程。一项较大的工程或者任务都可以分为若干个小的子工程或者子任务,称这些小的工程或任务为“活动”。其中,有的活动可以同时进行,有的则必须按一定的先后顺序进行。例如,计算机应用专业的学生,必须按照教学计划学完一系列基础课和专业课才能毕业。可以把这个过程看成是一项工程,而学习每门课程就是一个活动。表6.1列出了若干课程的名称与相应代号。其中,有些课程是基础课,它独立于其他课程,如“计算机数学”;而另一些课程则必须学完它的先修课程后才能进行,如学习“数据结构”之前必须先学“C语言程序设计”。这些先行条件定义了课程之间的优先关系。这些课程的优先关系可以用图6.20所示的有向图来表示。其中,顶点表示课程,有向边表示先行条件。若课程i为课程j的先行课程,则必然存在弧<i,j>。

slide58
若用图中的顶点来表示活动,用弧表示活动之间的优先关系,则这样的有向图称为AOV(activity on vertex network)网。在AOV网中,若从顶点i到顶点j之间存在一条有向路径,则称顶点i是顶点j的前驱,顶点j是顶点i的后继。若<i,j>是网中的一条弧,则称顶点i是顶点j的直接前驱,顶点j是顶点i的直接后继。

表6.1计算机应用专业的学生必须完成课程的名称与相应代号

slide59
图6.20 表示课程之间的优先关系的AOV网

在AOV网中,不应该出现有向环,因为有向环的存在,表明某项活动以其本身的完成作为先决条件。显然,若设计这样的流程图,工程将永远不会结束。而对程序的数据流图来说,则表明存在一个死循环。因此,对给定的AOV网应首先判定网中是否存在环。检测的一个方法是:

slide60
把AOV网中各个顶点排成一个线性序列,使得在此序列中顶点之间的前驱和后继关系都得到满足,即在AOV网中,若活动i是活动j的前驱,则在序列中活动i必在活动j前面。若有向图无环,则可构造一个包含图中所有顶点的线性序列。具有上述特性的线性序列称为拓扑有序序列。对AOV网构造拓扑有序序列的操作称为拓扑排序。若AOV网有环,则找不到该网的拓扑有序序列。反之,任何无环有向图,其所有顶点都可以排在一个拓扑有序序列里。例如,对图6.20的AOV网进行拓扑排序,可以得到下面两个拓扑有序序列:把AOV网中各个顶点排成一个线性序列,使得在此序列中顶点之间的前驱和后继关系都得到满足,即在AOV网中,若活动i是活动j的前驱,则在序列中活动i必在活动j前面。若有向图无环,则可构造一个包含图中所有顶点的线性序列。具有上述特性的线性序列称为拓扑有序序列。对AOV网构造拓扑有序序列的操作称为拓扑排序。若AOV网有环,则找不到该网的拓扑有序序列。反之,任何无环有向图,其所有顶点都可以排在一个拓扑有序序列里。例如,对图6.20的AOV网进行拓扑排序,可以得到下面两个拓扑有序序列:

(C1,C2,C11,C3,C4,C5,C6,C8,C12,C7,C9,C10)

和(C1,C3, C2,C4,C5, C11,C6,C8,C12,C7,C9,C10)

显然,一个AOV网的拓扑有序序列是不唯一的。对图6.20的AOV网还可以构造其他的拓扑有序序列。

对AOV网进行拓扑排序的方法和步骤是:

1从AOV网中选择一个没有前驱(即入度为0)的顶点并且输出之。

slide61
2从网中删去该顶点和所有以该顶点为尾的弧。

3重复上述两步,直至全部顶点均被输出,或者当前网中不再存在没有前驱的顶点为止。操作结果的前一种情况说明网中不存在有向回路,拓扑排序成功;后一种情况说明网中存在有向回路。

下面的图6.21给出了一个AOV网实施上述步骤的例子。

slide63
这样得到的一个拓扑排序序列为:v0,v5,v3,v2,v1,v4。这样得到的一个拓扑排序序列为:v0,v5,v3,v2,v1,v4。

为了实现拓扑排序,针对上述三步操作,我们采用邻接表作为有向图的存储结构,并且在表头向量中增设一个入度域(id),用来存放图中各顶点的入度;实现拓扑排序可设一个栈,用来存放入度为0的顶点,例如图6.21中的AOV网的邻接表和栈的初始状态如图6.22(a)所示。

这样,入度域为0的表结点即是无前驱的顶点,删除该顶点以及以它为尾的弧的操作,则可转换为将它的所有弧头顶点的入度减1来实现。

下面跟踪描述拓扑排序的全过程:

1将入度为0的顶点压栈,如图6.22(a)所示。

2取栈顶元素v0,输出v0,删除v0和所有以它为始点的弧e1,e2,e3,v1的入度减1,v2的入度减1,v2的入度变为0,v2入栈,v3的入度减1,如图6.22(b)所示。

3取栈顶元素v2,输出v2,删除v2和所有以它为始点的弧e7,e8,v1的入度减1,v1的入度为0,v1入栈,v4的入度减1,如图6.22(c)所示。

4取栈顶元素v1,输出v1,删除v1,没有以它为始点的弧,如图6.22(d)所示。

slide64
5取出栈顶元素v5,输出v5,删除v5和所有以它为始点的弧e4,e6,v4的入度减1,v3的入度减1, v3的入度变为0, v3入栈,如图6.22(e)所示。

6取栈顶元素v3,输出v3,删除v3和所有以它为始点的弧e5, v4的入度减1,v4的入度变为0,v4入栈,如图6.22(f)所示。

7取栈顶元素v4,输出v4,删除v4,没有以它为始点的弧,栈空,如图6.22(g)所示。

8栈空,算法结束。拓扑序列是:v0,v2,v1, v5, v3, v4。

(a)的邻接链表和栈的初始状态

slide66
本章小结

图是一种复杂的非线性数据结构。在图形结构中,任意两个顶点之间都可能相关,图形结构可以描述各种复杂的数据对象,并且图的应用也越来越受到人们的关注,目前已经被广泛应用于自然科学、社会科学和人文科学之中。在计算机科学与技术领域中,也常常需要表示不同事物之间的关系,图是描述这类关系的一个十分自然的模型。

要求掌握图的概念、图的存储结构、图的深度优先和广度优先搜索算法以及图的应用。

实 训

一、实训目的

1.掌握图的基本术语。

2.掌握图的存储方式。

3.掌握图的遍历。

slide67
二、实训内容

图的深度优先遍历

三、实训过程

1.算法分析:

图的存储结构采用邻接矩阵表示法。

2.算法提示:

#define MAXVEX 100 /*图的最大顶点数*/

typedef struct

{ /*图的邻接矩阵存储*/

int a[MAXVEX][MAXVEX];

int vex;

}

graph;

int visited[MAXVEX];

void DFS(graph G,int i)

/*从顶点i出发,对图G进行深度优先遍历,输出一个连通分量*/

slide68
visited[i]=1; /*结点已访问,置其为1*/

void DFStravse(graph G) /*对图进行深度优先遍历*/

{

确定从G中某一顶点v0出发,访问v0;

visited[v0]=1;

找出G中v0的第一个邻接点→w;

while(w存在)do

{ if visited[w]==0 继续进行深度优先搜索;

找出G中v0的下一个邻接顶点→w;

}

}

四、实训总结

通过本实训的实际操作,使读者掌握图的深度优先遍历算法描述,并用相关C语言程序设计的语法规则编写出可以上机调试运行的程序代码。熟悉图的存储结构,采用二维数组所表示的邻接矩阵。

slide69
思考与习题

一、填空题

1图有____、____ 等存储结构,遍历图有____、____等方法。

2.有向图G用邻接矩阵存储,其第i行的所有元素之和等于顶点i的____。

3.如果n个顶点的图是一个环,则它有____棵生成树。

4. n个顶点e条边的图,若采用邻接矩阵存储,则空间复杂度为____。

5. n个顶点e条边的图,若采用邻接表存储,则空间复杂度为____。

6.设有一稀疏图G,则G采用____存储较省空间。

7.设有一稠密图G,则G采用____存储较省空间。

8.图的逆邻接表存储结构只适用于____图。

9. 图的深度优先遍历序列____唯一的。

10.n个顶点e条边的图采用邻接矩阵存储,广度优先遍历算法的时间复杂度为____;若采用邻接表存储,该算法的时间复杂度为_____。

slide70
11.用普里姆(Prim)算法求具有n个顶点e条边的连通图的最小生成树的时间复杂度为____;用克鲁斯卡尔(Kruskal)算法的时间复杂度是____。

12.若要求一个稀疏图G的最小生成树,最好用____算法来求解。

13.若要求一个稠密图G的最小生成树,最好用____算法来求解。

14. 用Dijkstra算法求某一顶点到其余各顶点间的最短路径是按路径长度____的次序来得到最短路径的。

二、选择题

1.在一个图中,所有顶点的度数之和等于图的边数的____倍。

A1/2 B 1 C 2 D 4

2.在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的____倍。

A1/2 B1 C2 D4

slide71
3.有8个结点的无向图最多有____条边。

A14 B28 C56 D112

4.有8个结点的无向连通图最少有___条边。

A5 B6 C7 D8

5.有8个结点的有向完全图有___条边。

A14 B28 C56 D112

6.用邻接表表示图进行广度优先遍历时,通常是采用___来实现算法的。

A栈 B队列 C树 D图

7.用邻接表表示图进行深度优先遍历时,通常是采用___来实现算法的。

A栈 B队列 C树 D图

8.已知图的邻接矩阵,根据其存储的算法思路,则从顶点v0出发,按深度优先遍历的结点序列是___。

slide72

Av0 v2 v4 v3 v1 v5 v6

Bv0 v1 v3 v6 v5 v4 v2

Cv0 v4 v2 v3 v1 v6 v5

Dv0 v3 v6 v1 v5 v4 v2

9已知图的邻接矩阵同上述8题,根据其存储算法,则从顶点v0出发,按广度优先遍历的结点序列是___。

A v0 v2 v4 v3 v1 v6 v5

B v0 v1 v3 v5 v6 v4 v2

C v0 v1 v2 v3 v4 v6 v5

D v0 v1 v2 v3 v4 v5 v6

slide73
10.已知图的邻接表如图6.23所示,根据其存储的算法,则从顶点v0出发按深度优先遍历的结点序列是____。10.已知图的邻接表如图6.23所示,根据其存储的算法,则从顶点v0出发按深度优先遍历的结点序列是____。

图6.23 图的邻接表

A v0 v1 v3 v2 B v0 v2 v3 v1

C v0 v3 v2 v1 D v0 v1 v2 v3

slide74
11.已知图的邻接表如图6.24所示,根据其存储的算法,则从顶点v0出发,按广度优先遍历的结点序列是____。11.已知图的邻接表如图6.24所示,根据其存储的算法,则从顶点v0出发,按广度优先遍历的结点序列是____。

图6.24 图的邻接表

Av0 v3 v2 v1 B v0 v1 v2 v3

C v0 v1 v3 v2 D v0 v3 v1 v2

12.深度优先遍历类似于二叉树的____。

A 先序遍历 B 中序遍历 C 后序遍历 D 层次遍历

13.广度优先遍历类似于二叉树的____。

A 先序遍历 B 中序遍历 C 后序遍历 D 层次遍历

slide75
三、简答题

1.对于图6.25所示的有向图,试给出:

图6.25 有向图

(1)每个顶点的入度和出度;

(2)邻接矩阵;

(3)邻接表;

(4)逆邻接表;

(5)强连通分量。

slide76
2.设无向图如图6.26所示,试给出:

(1)邻接矩阵;

(2)邻接表;

(3)从a出发的“深度优先”遍历序列;

(4)从a出发的“广度优先”遍历序列。

图6.26 无向图

slide77

3.请对图6.27的无向带权图:

(1)写出它的邻接矩阵,并按普里姆算法求其最小生成树;

(2)写出它的邻接表,并按克鲁斯卡尔算法求其最小生成树。

图6.27 无向带权图

slide78
4.试利用Dijkstra算法求图6.28中从顶点a到其他各顶点间的最短路径,写出执行算法过程中各步的状态。

图6.28 有向带权图

slide79
四、算法题

1.试在无向图的邻接矩阵和邻接表上实现如下算法:

(1)往图中插入一个顶点;

(2)往图中插入一条边;

(3)删去图中某顶点;

(4)删去图中某条边。

2.试以邻接表和邻接矩阵为存储结构,分别写出基于DFS和BFS遍历的算法来判别顶点vi和vj(i≠j)之间是否有路径。

3.写一算法求连通分量的个数并输出各连通分量的顶点集。

4.设图中各边上的权值相等,试以邻接矩阵和邻接表为存储结构,分别写出算法:

(1)求顶点vi到顶点vj(i≠j)的最短路径。

(2)求源点vi到其余各顶点的最短路径。

要求输出路径上的所有顶点(提示:利用BFS遍历的思想)。