数据结构第七章图13节

第一节图的定义一、逻辑结构

1、逻辑结构

①定义:G=(V,E)。V是顶点集,E是顶点间二元关系的集合。

(内涵越小,外延越大)

②与树的区别:

①树有特殊的根结点;

②树的结点和关系能分成互不相交的若干子集。

③图的分类:

无向图

有向图

边:二元关系是无序的。

弧:二元关系是有序的。

(vi,vj):vi,vj互为邻接点

vi,vj:弧头vj、弧尾vi

G1=(V1,E1)

V1={v1,v,v3,v}

E1={(v1,v),(v1,v3),

(v1,v),(v,v3),

(v,v),(v3,v)}

G=(V,E)

V={v1,v,v3,v}

E={v1,v,v,v1,

v,v3,v,v3}

二、基本操作

①对顶点的操作:

InsertVex、DeleteVex、GetVex、SetVex

②对弧/边的操作:

InsertArc、DeleteArc、GetArc、SetArc

③对整体的操作(遍历):

深度遍历DFSTraverse、广度遍历BFSTraverse

三、常见应用

①信息的组织:

家庭照片管理(与个人照片管理的差别)

②运输问题:

从南京到泰州,最近的路线?换车最少的路线?

电子邮件的路由选择?

③网络的规划:

小区设店的位置选择?

区域规划、城市规划

计算机网络的规划

④进度组织:

工程进度管理

并行计算问题

四、概念术语

思路:考虑图的复杂应用,提供简化问题的思路。

1、图的分类

着眼点:存储结构的选择。

无向完全图

边数:n*(n-1)/

有向完全图

弧数:n*(n-1)

稀疏图

边数≈顶点数

稠密图

边数≈顶点数

带权图

边或顶点带权值

着眼点:图的分解。

子图

V(B)∈V(A),E(B)∈E(A),称图B是图A的子图。

、顶点的参数

无向图中,依附于某顶点的边数

入度

有向图中,以某顶点为弧尾的弧数

出度

有向图中,以某顶点为弧头的弧数

度的应用:以下哪个图能够一笔画完成?为什么?

一笔画问题的本质:图结构中的边遍历问题。

应用领域:车间/厂房布置、行走路线的安排…

3、有关路径

着眼点:顶点间的联系。

顶点间路径

Vi,……,Vj

顶点间连通

若从Vi到Vj有路径,称Vi到Vj是连通的。

路径长度

路径上边/弧的数目。

简单路径

路径中所有顶点各不相同。

回路

路径中,起点和终点是同一顶点。

简单回路

除起点和终点外,其余顶点各不相同。

、有关连通

着眼点:将不连通图简化为连通图。

连通图

无向图中,任意二个顶点之间是连通的。

强连通图

有向图中,任意二个顶点之间存在来往路径。

第二节图的存储结构

存储结构应该包含:

①顶点的信息;

②边/弧的信息;

③权的信息。

一、数组表示法

1、存储结构

#defineMAX_VERTEX//最大顶点个数

typedefstructArcCell//边、弧结构

{VRTypeadj;//权值

InfoType*info;//指向更多信息

}ArcCell;

typedefstruct

{VertexTypevexs[MAX_VERTEX];//顶点向量

ArcCellarcs[MAX_VERTEX][MAX_VERTEX];//邻接矩阵

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

}MGraph;//arcs[i][j]:顶点i-顶点j

空间复杂度:O(n*n)。

intcost[N][N]={{0,1,1,0},

{1,0,0,1},

{1,0,0,1},

{0,1,1,0},

};

intcost[N][N]={{0,,,M},

{,0,M,8},

{,M,0,1},

{M,8,1,0},

};

intcost[N][N]={{0,,,M},

{M,0,M,8},

{M,M,0,M},

{M,M,1,0},

};

优缺点:

操作方便,适合稠密图。

无向图的arcs[][]为对称矩阵,空间浪费。

当点多边少时,空间浪费多。

、算法思考

针对以上三图的存储结构,分析:

①在无向图中,如何求顶点i的度?

②在有向图中,如何求顶点i的入度、出度?

二、邻接表

1、结构分析

图的变化特征:顶点变化少,关系变化多。

顶点表:顺序结构。边/弧表:动态链表。

typedefstructArcNode//边、弧结构

{intadjvex;//邻接点、弧头的编号

InfoType*info;

structArcNode*nextarc;

}ArcNode;

typedefstructVexNode//顶点结构

{VertexTypedata;

ArcNode*firstarc;//指向出边表

}VexNode;

typedefstruct//图的邻接表结构

{VexNode*vertexes;

intvexnum,arcnum;

}ALGraph;

带权图的邻接表

、建立有向图邻接表的算法

①初始化一个无关系的邻接表结构

voidALGraph_Init(ALGraphG,VertexTypedata[],intn)

{G.vexnum=n;G.arcnum=0;//n为顶点数

G.vertexes=(VexNode*)malloc(n*sizeof(VexNode));

for(i=0;in;i++)//初始化空关系图

{G.vertexes[i].data=data[i];

G.vertexes[i].firstarc=NULL;

}

}

②插入一个弧v1,v

voidALGraph_Insert(ALGraphG,intv1,intv)

{ArcNode*p;

p=(ArcNode*)malloc(sizeof(ArcNode));

p-adjvex=v;

p-nextarc=G.vertexes[v1].firstarc;

G.vertexes[v1].firstarc=p;//首插入

G.arcnum++;

}

提醒:用不同插入方法,得到邻接表不一样。

3、邻接表的简单应用

①在无向图中,求顶点i的度?

在有向图中,求顶点i的出度?

intALGraph_OutDegree(ALGraphG,inti)

{intn;ArcNode*p;

p=G.vertexes[i].firstarc;

for(n=0;p;p=p-nextarc)n++;

return(n);

}

②在有向图中,如何求顶点i的入度?

intALGraph_InDegree(ALGraphG,inti)

{ArcNode*p;intk,n=0;

for(k=0;kG.vexnum;k++)

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

if(p-adjvex==i)n++;

return(n);

}

三、逆邻接表

1、结构分析

弧表中的结点是弧尾。

邻接表(出边表)

逆邻接表(入边表)

、算法思考

如何求入度、出度?与邻接表恰好相反

第三节图的遍历

图遍历定义:从某顶点出发,对每个顶点访问且仅访问一次。

图遍历与树遍历的比较:

区别:

可能回到起点。因为图不能划分为若干个顶点、关系互不相交的子集。

扩展

对访问过的顶点作标记,并加以识别。

本节以邻接表为基础讨论算法程序。也可采用其他结构。

一、深度优先搜索DFS(DepthFirstSearch)

1、算法

①设所有顶点都未曾被访问;(设置一个标记数组)

②从起点v出发,访问此顶点,同时设置访问标记;

③依次从v的未被访问过的邻接点出发进行DFS;

(效果:所有与v连通的顶点都被访问过)

④若所有顶点都已访问,则完成;否则,另择起点v,转至②。

例:已知邻接表,求遍历序列。

以顶点0为起点的DFS:0,1,,3,

以顶点3为起点的DFS:3,1,,,0

、递归程序

类似于树的递归遍历

Booleanvisited[MAX];inttime=0;//用于跟踪程序

//帽子函数

voidDFSTraverse(ALGraphG)

{if(G.vexnum==0)return;

for(v=0;vG.vexnum;v++)visited[v]=FALSE;//实现步骤①

for(v=0;vG.vexnum;v++)//实现步骤④

if(visited[v]==FALSE)DFS(G,v);

}

//核心函数:遍历顶点v所在的连通分量

voidDFS(ALGraphG,intv)//v为起点序号

{ArcNode*p;intw;

printf(v);visited[v]=TRUE;//实现步骤②

//实现步骤③

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

{w=p-adjvex;

if(visited[w]==FALSE)

DFS(G,w);

}

}

思考:

时间复杂度?O(e)e为边/弧数

二、广度优先搜索BFS(breadthfirstsearch)

相当于树的层次遍历。

1、算法

①设所有顶点都未曾被访问;

②将起点编号加入队列,同时设置访问标记;

③取队首元素,设为v,访问结点v;

④依次将v的各个未被访问过的顶点加入队列,同时设置访问标记;

⑤若队列不空,则循环执行③④,否则⑥;

⑥若所有顶点都已访问,则完成;否则,另择起点V,转至②。

例:已知邻接表,求遍历序列。

以顶点0为起点的BFS:0,1,3,,

以顶点3为起点的BFS:3,1,0,,

、程序

Booleanvisited[MAX];

//帽子函数

voidBFSTraverse(ALGraphG)

{if(G.vexnum==0)return;

for(v=0;vG.vexnum;v++)visited[v]=FALSE;//实现步骤①

for(v=0;vG.vexnum;v++)//实现步骤⑥

if(visited[v]==FALSE)BFS(G,v);

}

//核心函数:遍历顶点v所在的连通分量

//每个顶点出队列后,被访问

voidBFS(ALGraphG,intv)

{QueueQ;ArcNode*p;

Q_Init(Q);

Q_Enter(Q,v);visited[v]=TRUE;//步骤②

while(!Q_Empty(Q))//步骤⑤

{v=Q_Leave(Q);printf(v);//步骤③

for(p=G.vertices[v].firstarc;p;p=p-nextarc)//步骤④

{w=p-adjvex;

if(visited[w]==FALSE)

{Q_Enter(Q,w);visited[w]=TRUE;}

}

}

}

上机:以邻接表为结构存储图,深度、广度遍历之。









































北京哪里治疗白癜风比较好
治疗白癜风哪里比较好



转载请注明:http://www.92nongye.com/tlfc/204615003.html