数据结构详细教案图解析.docx

上传人:b****5 文档编号:3291917 上传时间:2022-11-21 格式:DOCX 页数:21 大小:62.41KB
下载 相关 举报
数据结构详细教案图解析.docx_第1页
第1页 / 共21页
数据结构详细教案图解析.docx_第2页
第2页 / 共21页
数据结构详细教案图解析.docx_第3页
第3页 / 共21页
数据结构详细教案图解析.docx_第4页
第4页 / 共21页
数据结构详细教案图解析.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

数据结构详细教案图解析.docx

《数据结构详细教案图解析.docx》由会员分享,可在线阅读,更多相关《数据结构详细教案图解析.docx(21页珍藏版)》请在冰豆网上搜索。

数据结构详细教案图解析.docx

数据结构详细教案图解析

 

数据结构教案

第七章图

第7章图

【学习目标】

  1.领会图的类型定义。

  2.熟悉图的各种存储结构及其构造算法,了解各种存储结构的特点及其选用原则。

  3.熟练掌握图的两种遍历算法。

  4.理解各种图的应用问题的算法。

【重点和难点】

  图的应用极为广泛,而且图的各种应用问题的算法都比较经典,因此本章重点在于理解各种图的算法及其应用场合。

【知识点】

  图的类型定义、图的存储表示、图的深度优先搜索遍历和图的广度优先搜索遍历、无向网的最小生成树、最短路径、拓扑排序、关键路径

【学习指南】

  离散数学中的图论是专门研究图性质的一个数学分支,但图论注重研究图的纯数学性质,而数据结构中对图的讨论则侧重于在计算机中如何表示图以及如何实现图的操作和应用等。

图是较线性表和树更为复杂的数据结构,因此和线性表、树不同,虽然在遍历图的同时可以对顶点或弧进行各种操作,但更多图的应用问题如求最小生成树和最短路径等在图论的研究中都早已有了特定算法,在本章中主要是介绍它们在计算机中的具体实现。

这些算法乍一看都比较难,应多对照具体图例的存储结构进行学习。

而图遍历的两种搜索路径和树遍历的两种搜索路径极为相似,应将两者的算法对照学习以便提高学习的效益。

【课前思考】

1.你有没有发现现在的十字路口的交通灯已从过去的一对改为三对,即每个方向的直行、左拐和右拐能否通行都有相应的交通灯指明。

你能否对某个丁字路口的6条通路画出和第一章绪论中介绍的"五叉路口交通管理示意图"相类似的图?

2.如果每次让三条路同时通行,那么从图看出哪些路可以同时通行?

同时可通行的路为:

(AB,BC,CA),(AB,BC,BA),(AB,AC,CA),(CB,CA,BC)

目录

第7章图1

7.1图的定义和基本术语1

7.2图的存储和创建2

7.2.1图的存储表示2

7.2.2图的创建4

7.3图的遍历5

7.3.1深度优先搜索5

7.3.2广度优先搜索6

7.4遍历算法的应用7

7.4.1应用问题概述7

7.4.2求一条包含图中所有顶点的简单路径8

7.4.3求距v0的各顶点中最短路径长度最长的一个顶点9

7.5图的连通性问题10

7.5.1无向图的连通分量和生成树10

7.5.2最小生成树11

7.6有向无环图及其应用12

第7章图

7.1图的定义和基本术语

1、图的特征

任意两个数据元素之间都可能相关。

结点之间的关系是多对多的。

G=(V,{E})

2、基本术语

结点:

顶点

结点间的关系:

无向图:

边(v,w),v与w互为邻接点,边(v,w)依附于顶点v,w,边(v,w)和顶点v,w相关联

v的度:

和v相关联的边的数目。

有向图:

,v弧尾,w弧头,顶点v邻接到顶点w,顶点w邻接自顶点v,弧和顶点v,w相关联。

v的入度:

以v为弧头的弧的数目;v的出度:

以v为弧尾的弧的数目;

v的度:

v的入度与出度之和。

路径、回路(环)、简单路径、简单回路(简单环)

连通性:

若从顶点v到顶点v’有路径,则称v和v’是连通的

图的规模:

顶点数n、边(弧)数e、顶点的度(有向图:

入度/出度)

子图:

G’=(V’,{E’}),G=(V,{E}),若V’V且E’E,则称G’是G的子图。

图的分类:

1)关系的方向性(无向/有向)、关系上是否有附加的数——权(图/网)

有向图、无向图、有向网、无向网

2)边(弧)数:

完全图(边数=n(n-1)/2的无向图)、有向完全图(弧数=n(n-1)的有向图)

稀疏图(enlogn)

3)连通性:

无向图:

连通图(任意两顶点都是连通的)、连通分量(极大连通子图)、生成树(极小连通子图)、生成森林

有向图:

强/弱连通图、强连通分量、生成树(极小连通子图)、生成森林

3、抽象数据类型定义

ADTGraph{

数据对象V:

V是具有相同特性的数据元素的集合,称为顶点集。

数据关系R:

R={VR}

VR={|v,wV且P(v,w),表示从v到w的弧,谓词P(v,w)定义了弧的意义或信息}

基本操作:

CreateGraph(&G,V,VR)

初始条件:

V是图的顶点集,VR是图中弧的集合

操作结果:

按V和VR的定义构造图G

DestroyGraph(&G)

初始条件:

图G存在

操作结果:

销毁图G

LocateVex(G,u)

初始条件:

图G已存在,u和G中顶点有相同特征

操作结果:

若G中存在顶点u,则返回该顶点在图中位置,否则返回其它信息

GetVex(G,v)

初始条件:

图G存在,v是G中某个顶点

操作结果:

返回v的值

PutVex(&G,v,value)

初始条件:

图G存在,v是G中某个顶点

操作结果:

对v赋值value

FirstAdjVex(G,v)

初始条件:

图G存在,v是G中某个顶点

操作结果:

返回v的第一个邻接顶点。

若顶点在G中没有邻接顶点,则返回“空”

NextAdjVex(G,v,w)

初始条件:

图G存在,v是G中某个顶点,w是v的邻接顶点

操作结果:

返回v的(相对于w的)下一个邻接顶点。

若w是v的最后一个邻接点,则返回“空”

InsertVex(&G,v)

初始条件:

图G存在,v和G中顶点有相同特征

操作结果:

在图中增添新顶点v

DeleteVex(&G,v)

初始条件:

图G存在,v是G中某个顶点

操作结果:

删除G中顶点v及其相关的弧

InsertArc(&G,v,w)

初始条件:

图G存在,v和w是G中两个顶点

操作结果:

在图G中增添弧,若G是无向的,则还应增添对称弧

DeleteArc(&G,v,w)

初始条件:

图G存在,v和w是G中两个顶点

操作结果:

删除G中的弧,若G是无向的,则还应删除对称弧

DFSTraverse(G,v,visit())

初始条件:

图G存在,v是G中某个顶点,visit是对顶点的应用函数

操作结果:

从顶点v起深度优先遍历图G,并对每个顶点调用函数visit()一次且至多一次。

一旦visit()失败,则操作失败

BFSTraverse(G,v,visit())

初始条件:

图G存在,v是G中某个顶点,visit是对顶点的应用函数

操作结果:

从顶点v起广度优先遍历图G,并对每个顶点调用函数visit()一次且至多一次。

一旦visit()失败,则操作失败

}ADTGraph

7.2图的存储和创建

7.2.1图的存储表示

1、图的存储表示分析

∵顶点之间的关系是多对多的(m:

n),由于m和n都是不定的,无法给出一个这种多对多的关系向线性关系的映射公式

∴图中的关系不能通过顺序映像(即通过顶点之间的存储位置反映顶点之间的逻辑关系)反映;必须另外引入存储空间反映顶点之间的邻接关系。

图的存储结构:

1)顶点信息;2)边(弧)信息;3)整体信息:

顶点数、边(弧)数、图的种类(有向图、无向图、有向网、无向网)

顶点集的存储:

∵图的应用中,顶点集动态变化的几率十分小

∴顶点集可以采用顺序表存储,按预先估计的最大顶点数分配空间

(顺序表和链表:

若数据元素集是静态的,采用顺序表要好(随机存取);若数据元素集是动态的,则采用链表要好(动态分配与释放))

#defineMAX_VERTEX_NUM20/*最大顶点数*/

注意:

顺序表与顺序映像之间的区别

关系集的存储:

在顶点确定的情况下,边或弧的数目也是不定的;且在实际应用中,可能会改变图中顶点之间的关系。

邻接矩阵表示法:

矩阵中的第i行第j列的元素反映图中第i个顶点到第j个顶点是否存在弧;若存在,其附加的信息是什么。

邻接表表示法:

将每一顶点的邻接点位置串成一个链,称为邻接表。

对于有向图/网来说,该邻接表反映的是顶点的出边表。

typedefenum{DG,DN,AG,AN}GraphKind;/*{有向图,有向网,无向图,无向网}*/

2、邻接矩阵表示法(数组表示法)

无向图/网:

对称矩阵有向图/网:

非必是对称矩阵

图:

邻接关系用1/0表示

网:

邻接关系需要进一步反映权值,用INFINITY表示无穷大,反映顶点之间无邻接关系

#defineINT_MAX32767/*最大整数*/

#defineINFINITYINT_MAX

1)邻接矩阵

typedefstructArcCell{

intadj;//顶点间关系,无权图:

0-不相邻,1-相邻

//有权图,权值,INFINITY-不相邻

InfoType*info;//该弧相关信息的指针

}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

2)图的整体结构

typedefstruct{

VertexTypevexs[MAX_VERTEX_NUM];/*有效的顶点下标从0开始*/

AdjMatrixarcs;/*关系集*/

intvexnum,arcnum;/*顶点数、边/弧数*/

GraphKindkind;/*图的种类*/

}MGraph;

3、邻接表表示法

无向图/网:

边表,表结点的个数为边数的两倍

有向图/网:

出边表,表结点的个数为弧数

1)邻接表的表结点

typedefstructArcNode{

intadjvex;/*弧所指向的顶点的位置*/

structArcNode*nextarc;/*指向下一条弧的指针*/

InfoType*info;

}ArcNode;

2)邻接表的头结点

typedefstructVNode{

VertexTypedata;/*顶点信息*/

ArcNode*firstarc;/* 邻接表指针*/

}VNode,AdjList[MAX_VERTEX_NUM];

3)图的整体结构

typedefstruct{

AdjListvertices;

intvexnum,arcnum;

GraphKindkind;

}ALGraph;

4、邻接矩阵与邻接表的对比

假设图为G,顶点数为n,边/弧数为e。

A邻接矩阵

B邻接表

存储空间

O(n+n2)

O(n+e)

图的创建算法

T1(n)=O(e+n2)或T2(n)=O(e*n+n2)

T1(n)=O(n+e)或T2(n)=O(e*n)

T1(n)是指在输入边/弧时,输入的顶点信息为顶点的编号;而T2(n)则指在输入边/弧时,输入的为顶点本身的信息,此时需要查找顶点在图中的位置

无向图中求第i顶点的度

(第i行之和)或

(第i列之和)

G.vertices[i].firstarc所指向的邻接表包含的结点个数

无向网中求第i顶点的度

第i行/列中adj值不为INFINITY的元素个数

有向图中求第i顶点的入/出度

入度:

(第i列)

出度:

(第i行)

入度:

扫描各顶点的邻接表,统计表结点的adjvex为i的表结点个数T(n)=O(n+e)

出度:

G.vertices[i].firstarc所指向的邻接表包含的结点个数

有向网中求第i顶点的入/出度

入度:

第i列中adj值不为INFINITY的元素个数

出度:

第i行中adj值不为INFINITY的元素个数

统计边/弧数

无向图:

无向网:

G.arcs中adj值不为INFINITY的元素个数的一半

有向图:

有向网:

G.arcs中adj值不为INFINITY的元素个数

无向图/网:

图中表结点数目的一半

有向图/网:

图中表结点的数目

结论:

邻接矩阵适于稠密图的存储,邻接表适于稀疏图的存储;邻接表求有向图的顶点的入度不方便,要遍历各个顶点的邻接表。

7.2.2图的创建

基本过程:

1)输入图的类型,根据类型选择相应的创建算法

2)输入图的顶点数,边/弧数

3)输入并存储顶点信息

4)输入边/弧所关联的顶点对,将边或弧的信息存储到邻接矩阵/邻接表中

图的存储结构不同、图的类型不同,都会影响创建算法的实现细节;但是,图的总体创建流程是一致的(如上)。

示例:

用邻接矩阵表示法构造有向网G

StatusCreateMDG(MGraph&G){

/*步骤2:

输入图的顶点数、边/弧数*/

scanf(&G.vexnum,&G.arcnum,&IncInfo);/*IncInfo为0则各弧不含其它信息*/

/*步骤3:

输入并存储顶点信息*/

for(i=0;i

/*步骤4:

输入并存储边/弧信息*/

for(i=0;i

for(j=0;j

G.arcs[i][j]={INFINITY,NULL};

for(k=0;k

scanf(&v1,&v2,&w);

i=LocateVex(G,v1);j=LocateVex(G,v2);

G.arcs[i][j].adj=w;

if(IncInfo)Input(*G.arcs[i][j].info);/**G.arcs[i][j].info要求G.arcs[i][j].info指向的空间在调用Input()前分配*/

}

}

7.3图的遍历

7.3.1深度优先搜索

1、分析

·类似于树的先序遍历

·引入访问标志数组visit[0:

n-1],区分顶点是否已被访问

·非连通图,需引入多个深度优先搜索的起始顶点

·递归算法或基于栈的非递归算法

2、基于ADTGraph的DFS算法

Booleanvisited[MAX_VERTEX_NUM];

voidDFSTraverse(GraphG,Status(*Visit)(GraphG,intv))

{

for(v=0;v

for(v=0;v

if(!

visited[v])DFS(G,v,Visit);

}

voidDFS(GraphG,intv,Status(*Visit)(GraphG,intv))

{

visited[v]=TRUE;Visit(G,v);

for(w=FirstAdjVex(G,v);w;w=NextAdjVex(G,v,w))

if(!

visited[w])DFS(G,w,Visit);

}

3、基于某种存储结构的DFS算法

根据选择的存储结构,决定FirstAdjVex()和NextAdjVex()的实现,重新整合算法。

如采用邻接矩阵表示法表示的图,则DFS算法如下:

voidDFS(MGraphG,intv,Status(*Visit)(MGraphG,intv))

{

visited[v]=TRUE;Visit(G,v);

for(w=0;w

if(G.arcs[v][w].adj&&!

visited[w])DFS(G,w,Visit);

}

如采用邻接表表示法表示的图,则DFS算法如下:

voidDFS(ALGraphG,intv,Status(*Visit)(ALGraphG,intv))

{

visited[v]=TRUE;Visit(G,v);

for(p=G.vertices[v].firstarc;p;p=p->nextarc)

if(!

visited[p->adjvex])DFS(G,p->adjvex,Visit);

}

7.3.2广度优先搜索

1、分析

·类似于树的层次遍历

·引入visited访问标志数组

·非连通图,需引入多个广度优先搜索的起始顶点

·引入队列保存“顶点已访问,但其邻接点未全访问”的顶点编号

2、基于ADTGraph的BFS算法

voidBFSTraverse(GraphG,Status(*Visit)(GraphG,intv))

{

for(v=0;v

InitQueue(Q);

for(v=0;v

if(!

visited[v]){

/*访问某连通分量的起始顶点,起点入队*/

visited[v]=TRUE;Visit(G,v);

EnQueue(Q,v);

while(!

QueueEmpty(Q)){

/*出队,访问出队元素的邻接点*/

DeQueue(Q,u);

for(w=FirstAdjVex(G,u);w;w=NextAdjVex(G,u,w))

if(!

visited[w]){

/*访问顶点u的尚未访问的邻接点并入队*/

visited[w]=TRUE;Visit(G,w);

EnQueue(Q,w);

}

}

}

}

3、基于某种存储结构的BFS算法

如采用邻接矩阵表示法表示的网,则算法如下:

voidBFSTraverse(MGraphG,Status(*Visit)(MGraphG,intv))

{

for(v=0;v

InitQueue(Q);

for(v=0;v

if(!

visited[v]){

/*访问某连通分量的起始顶点,起点入队*/

visited[v]=TRUE;Visit(G,v);

EnQueue(Q,v);

while(!

QueueEmpty(Q)){

/*出队,访问出队元素的邻接点*/

DeQueue(Q,u);

for(w=0;w

if(G.arcs[u][w].adj!

=INFINITY&&!

visited[w]){

/*访问顶点u的尚未访问的邻接点并入队*/

visited[w]=TRUE;Visit(G,w);

EnQueue(Q,w);

}

}

}

}

如采用邻接表表示法表示的网,则算法如下:

voidBFSTraverse(ALGraphG,Status(*Visit)(ALGraphG,intv))

{

for(v=0;v

InitQueue(Q);

for(v=0;v

if(!

visited[v]){

/*访问某连通分量的起始顶点,起点入队*/

visited[v]=TRUE;Visit(G,v);

EnQueue(Q,v);

while(!

QueueEmpty(Q)){

/*出队,访问出队元素的邻接点*/

DeQueue(Q,u);

for(p=G.vertices[u].firstarc;p;p=p->nextarc)

if(!

visited[p->adjvex]){

/*访问顶点u的尚未访问的邻接点并入队*/

visited[p->adjvex]=TRUE;Visit(G,p->adjvex);

EnQueue(Q,p->adjvex);

}

}

}

}

7.4遍历算法的应用

7.4.1应用问题概述

图的深度优先遍历:

1、求一条包含图中所有顶点的简单路径(简单回路)

2、判断图中是否存在环

3、求图中通过给定顶点vk的简单回路

4、判断是否存在从顶点vi到顶点vj的路径

5、判别v0和v1之间是否存在一条长度为k的路径

图的广度优先遍历:

1、判断是否存在从顶点vi到顶点vj的路径

2、求距v0的各顶点中最短路径长度最长的一个顶点。

3、求v0和v1之间的最短路径.

4、在顶点子集U中找出距离顶点v0最近的顶点

5、求顶点v0到其余每个顶点的最短路径

6、求距离顶点v0的最短路径长度为k的所有顶点

7.4.2求一条包含图中所有顶点的简单路径

1、思路

对于任意的有向图或无向图G,并不一定都能找到符合题意的简单路径。

这样的简单路径要求包含G.vexnum个顶点,且互不相同。

它的查找可以基于深度优先遍历。

在一个存在包含全部顶点的简单路径的图中,以下因素会影响该简单路径是否能顺利地查到:

1)起点的选择:

如图(a),其符合题意的一条简单路径如图(b)。

若起点为1,则不能找到符合题意的简单路径;

2)顶点的邻接点次序:

进一步考察图(a),即使以2为起点,但是2的邻接点选择的是1,而不是5,此时也不能找到符合题意的解。

在基于DFS的查找算法中,由于起点和邻接点的选取是与顶点和邻接点的存储次序以及算法的搜索次序有关,不可能依据特定的图给出特定的解决算法。

因此,在整个搜索中应允许有查找失败,此时可采取回溯到上一层的方法,继续查找其他路径。

这样,引入数组Path用来保存当前已搜索的简单路径上的顶点,引入计数器n用来记录当前该路径上的顶点数。

对DFS算法的修改如下:

1)计数器n的初始化,放在visited的初始化前后;

2)访问顶点时,增加将该顶点序号入数组Path中,计数器n++;判断是否已获得所求路径,是则输出结束,否则继续遍历邻接点;

3)某顶点的全部邻接点都访问后,仍未得到简单路径,则回溯,将该顶点置为未访问,计数器n--。

2、算法

/*邻接矩阵表示法,粗体字部分为在深度优先遍历上的增加或修改的步骤*/

voidHamilton(MGraphG)

{

for(i=0;i

visited[i]=FALSE;

n=0;

for(i=0;i

if(!

visited[i])DFS(G,i);

}

voidDFS(MGraphG,inti)

{

visited[i]=TRUE;

Path[n]=i;

n++;

if(n==G.v

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1