第6章 图 本章中介绍下列主要内容: 图的定义 图的存储结构 图的遍历操作 图的几个典型问题.

Slides:



Advertisements
Similar presentations
三级偏软考点. 第一章必考点 1. 计算机的进位数制 (1) 计算机中所有数据是二进制 0,1 表示 (2) 在现实生活中人们普遍使用十进制 如何把十进制转换成计算机所识别的二 进制?整数是除 2 取余法,小数是乘 2 取 整法.
Advertisements

阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
第七章 图 7.1 图的定义和术语 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图及其应用
复习:树 树的基本概念和术语 二叉树的概念及性质 二叉树的存储结构 遍历二叉树 线索二叉树 树的应用:哈夫曼树 顺序存储 链式存储 递归算法
丰富的图形世界(2).
最大团问题 回溯法应用 作者:余新华 时间:
图 2008赛前知识点梳理三.
初中数学八年级下册 (苏科版) 10.4 探索三角形 相似的条件(2).
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
树 无向树及其应用 生成树 根树及其应用.
数据结构 第7章 图.
第六章 图(一).
第七章 图 (Graph)
Ch.7 图 图是一种复杂的非线性结构 应用:AI、工程、数学、生物、计算机 结点间的逻辑关系:任两个结点都可能相关
第9章 图 图的基本概念 图的存储结构 图的实现 图的遍历 最小生成树 最短路径 拓扑排序 关键路径 主要知识点.
第七章 图 7.1 图的基本概念 7.2 图的存储表示 7.3 图的遍历 7.4 图的生成树 7.5 最短路径 7.6 拓扑排序
图(一).
第七章 图 1、图的基本概念 2、图的存储表示 3、图的遍历与连通性 4、最小代价生成树 5、最短路径问题 6、AOV网络和AOE网络.
图的遍历.
Chapter 6 Graphs.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
第七章 图.
7.1 抽象数据类型图的定义 7.2 图的存储表示 7.3 图的遍历 7.4 最小生成树 7.5 重(双)连通图和关节点
第七章 图.
第七章 图 知识点2:图的存储结构.
第七章 图 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
第7章 图 本章主题:图的基本概念、图的存储结构和图的常用算法 教学目的: 教学重点:图的各种存储方式及其运算
数据结构 复习课 王彦 博士,副教授
第七章 图.
数据结构 Data Structure CSU 主讲人:王国军,郑瑾 中南大学信息院计科系
第6章 图 北京师范大学 教育技术学院 杨开城.
数据结构 芦溪中学 胡小妹.
第7章 图 7.1 图的定义和术语 7.2 图的存储结构 7.3 图的遍历 7.4 图的连通性问题 7.5 有向无环图的应用
第七章 图.
动态规划(Dynamic Programming)
使用矩阵表示 最小生成树算法.
无向树和根树.
第 五 章 图 论 (第二部分) 1. 通路 2. 图的连通性.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
知识点回顾 拓扑排序 关键路径 应用领域、求解步骤、算法实现过程 应用领域 求解步骤
第八章 图 图的基本概念 图的存储表示 图的遍历与连通性 最小生成树 最短路径 活动网络.
Graphs.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
8.1 图的基本概念 8.2 图的存储结构 8.3 图的遍历 8.4 生成树 8.5 最短路径 8.6 拓扑排序 8.7 关键路径
数据结构学位考 复习课(3) 主要内容: 1. 图 2.查找、排序.
复习 图的定义和术语 图(Graph)、有向图、无向图、子图、有向完全图 、完全图、稀疏图、稠密图、权、网、邻接点、相关边、度、路径、路径长度、回路、简单路径、简单回路、连通、连通图、连通分量、强连通图、强连通分量、生成树 图的存储方法 给定一个图,画出邻接矩阵、邻接表 图的邻接矩阵和邻接表的存储算法.
顺序表的删除.
常宝宝 北京大学计算机科学与技术系 数据结构(六) 常宝宝 北京大学计算机科学与技术系
信号量(Semaphore).
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
图(二).
知识点回顾 图的深度优先和广度优先遍历思想 图的深度优先遍历算法(用邻接表作为存储结构) 图的广度优先遍历算法(用邻接矩阵作为存储结构)
3.16 枚举算法及其程序实现 ——数组的作用.
树和图 tree and graph 蔡亚星.
第七、八次实验要求.
第六章 图 本章的主要内容是: 图的逻辑结构 图的存储结构及实现 图的连通性 最小生成树 最短路径 AOV网与拓扑排序 AOE网与关键路径.
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
最小生成树.
基于列存储的RDF数据管理 朱敏
第七章 图 £7.1 图的定义和术语 £7.2 图的存储结构 £7.3 图的遍历 £7.4 图的连通性问题 £7.5 有向无环图及其应用
4.2 图的存储结构(cont.) v1 v2 v3 v4 v5 vertex= v1 v2 v3 v4 v5 v
第六章 图.
数据结构 第六章 图.
树的基本概念.
第三部分 图论 本部分主要内容 图的基本概念 树 欧拉图与哈密顿图 二部图与匹配 平面图 着色.
第7章 图.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
1、图的基本概念 2、图的存储结构 3、图的遍历与连通性
最小生成树 最优二叉树.
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
Presentation transcript:

第6章 图 本章中介绍下列主要内容: 图的定义 图的存储结构 图的遍历操作 图的几个典型问题

6.1 图的定义 6.2 图的存储结构 6.3 图的遍历 6.4 最小生成树问题 6.5 拓扑排序问题

6.1 图的定义 6.1.1 定义 图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

(a) (b) 图 6-1

在上面两个图结构中,一个是有向图,即每条边都有方向,另一个是无向图,即每条边都没有方向。 在有向图中,通常将边称作弧,含箭头的一端称为弧头,另一端称为弧尾,记作<vi,vj>,它表示从顶点vi到顶点vj有一条边。 若有向图中有n个顶点,则最多有n(n-1)条弧, 我们又将具有n(n-1)条弧的有向图称作有向完全图。 以顶点v为弧尾的弧的数目称作顶点v的出度,以顶点v为弧头的弧的数目称作顶点v的入度。 在无向图中,边记作(vi,vj),它蕴涵着存在< vi,vj>和<vj,vi>两条弧。若无向图中有n个顶点,则最多有n(n-1)/2条边,我们又将具有n(n-1)/2条边的无向图称作无向完全图。

与顶点v相关的边的条数称作顶点v的度。 路径长度是指路径上边或弧的数目。 若第一个顶点和最后一个顶点相同,则这条路径是一条回路。 若路径中顶点没有重复出现,则称这条路径为 简单路径。 在无向图中,如果从顶点vi到顶点vj有路径,则称vi和vj连通。如果图中任意两个顶点之间都连通,则称该图为连通图,否则,将其中的极大连通子图称为连通分量。 在有向图中,如果对于每一对顶点vi和vj,从vi到vj和从vj到vi都有路径,则称该图为强连通图;否则,将其中的极大连通子图称为强连通分量。

6.1.2 图的基本操作 基本操作: (1)创建一个图结构 CreateGraph(G) 6.1.2 图的基本操作 基本操作: (1)创建一个图结构 CreateGraph(G) (2)检索给定顶点 LocateVex(G,item) (3)获取图中某个顶点 GetVex(G,v) (4)为图中顶点赋值 PutVex(G,v,value) (5)返回第一个邻接点 FirstAdjVex(G,v) (6)返回下一个邻接点 NextAdjVex(G,v,w) (7)插入一个顶点 InsertVex(G,v) (8)删除一个顶点 DeleteVex(G,v) (9)插入一条边 InsertEdge(G,v,w) (10)删除一条边 DeleteEdge(G,v,w) (11)遍历图 Traverse(G,v)

6.2 图的存储结构 6.2.1 邻接矩阵 1. 有向图的邻接矩阵 具有n个顶点的有向图可以用一个nn的方形矩阵表示。假设该矩阵的名称为M,则当<vi,vj>是该有向图中的一条弧时,M[i,j]=1;否则M[i,j]=0。第i个顶点的出度为矩阵中第i行中“1”的个数;入度为第i列中“1”的个数,并且有向图弧的条数等于矩阵中“1”的个数。

1.2 无向图的邻接矩阵 具有n个顶点的无向图也可以用一个nn的方形矩阵表示。假设该矩阵的名称为M,则当(vi,vj)是该无向图中的一条边时,M[i,j]=M[j,i]=1;否则,M[i,j]=M[j,j]=0。第i个顶点的度为矩阵中第i 行中“1”的个数或第i列中“1”的个数。图中边的数目等于矩阵中“1”的个数的一半,这是因为每条边在矩阵中描述了两次。

图 6-4

图 6-5

在C 语言中,实现邻接矩阵表示法的类型定义如下所示: #define MAX_VERTEX_NUM 20 typedef struct graph{ EntryType item[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; int n; }Graph;

6.2.2 邻接表 边结点的结构为: adjvex是该边或弧依附的顶点在数组中的下标, next是指向下一条边或弧结点的指针。

图 6-6

构成一维数组的顶点结构为: item是顶点内容,firstedge是指向第一条边或弧结点的指针。 在C语言中,实现邻接表表示法的类型定义如下所示: #define MAX_VERTEX_NUM 30 //最大顶点个数 type struct EdgeNode{ //边结点

int adjvex; struct EdgeNode *next; }EdgeNode; typedef struct VexNode{ //顶点结点 EntryType item; EdgeNode *firstedge; }VexNode,AdjList[MAX_VERTEX_NUM]; 创建有向图和无向图邻接表的算法实现:

(1)创建有向图邻接表 void Create_adj(AdjList adj, int n) { for (i=0;i<n;i++){ //初始化顶点数组 scanf(&adj[i].item); adj[i].firstedge=NULL; } scanf(&i,&j); //输入弧

while (i) { s=(EdgeNode*)malloc(sizeof(EdgeNode)); //创建新的弧结点 s->adgvex=j-1; s->next=adj[i-1].firstedge; //将新的弧结点插入到相应的位置 adj[i-1].firstegde=s; scanf(&i,&j); //输入下一条弧 }

(2)创建无向图的邻接表 void Create_adj(AdjList adj, int n) { for (i=0;i<n;i++){ //初始化邻接表 scanf(&adj[i].item); adj[i].firstedge=NULL; } scanf(&i,&j); //输入边

while (i) { s1=(EdgeNode*)malloc(sizeof(EdgeNode)); s1->adgvex=j-1; s2=(EdgeNode*)malloc(sizeof(EdgeNode)); s2->adgvex=i-1; s1->next=adj[i-1].firstedge; adj[i-1].firstegde=s1; s2->next=adj[j-1].firstedge; adj[j-1].firstegde=s2; scanf(&i,&j); }

6.3 图的遍历 6.3.1 深度优先遍历 常见的图遍历方式有两种:深度优先遍历和广度优先遍历,这两种遍历方式对有向图和无向图均适用。 6.3 图的遍历 常见的图遍历方式有两种:深度优先遍历和广度优先遍历,这两种遍历方式对有向图和无向图均适用。 6.3.1 深度优先遍历 深度优先遍历的思想类似于树的先序遍历。其遍历过程可以描述为:从图中某个顶点v出发,访问该顶点,然后依次从v的未被访问的邻接点出发继续深度优先遍历图中的其余顶点,直至图中所有与v有路径相通的顶点都被访问完为止。

下面我们讨论一下如何实现深度优先算法。 为了便于在算法中区分顶点是否已被访问过,需要创建一个一维数组visited[0..n-1](n是图中顶点的数目),用来设置访问标志,其初始值visited[i](0≤i≤n-1)为“0”,表示邻接表中下标值为i的顶点没有被访问过,一旦该顶点被访问,将visited[i]置成“1”。 int visited[0..n-1]={0,0,...0}; void DFS(AdjList adj,int v) {//v是遍历起始点的在邻接表中的下标值,其下标从0开始 visited[v]=1; visite(adj[v].item); for (w=adj[v].firstedge;w;w=w->next) if (!visited[w->adjvex]) DFS(adj,w->adjvex); }

对于无向图,这个算法可以遍历到v顶点所在的连 通分量中的所有顶点,而与v顶点不在一个连通分量中 的所有顶点遍历不到;而对于有向图可以遍历到起始 顶点v能够到达的所有顶点。若希望遍历到图中的所有 顶点,就需要在上述深度优先遍历算法的基础上,增 加对每个顶点访问状态的检测: int visited[0..n-1]={0,0,...0}; void DFSTraverse(AdjList adj) { for (v=0;v<n;v++) if (!visited[v]) DFS(adj,v); }

6.3.2 广度优先遍历 对图的广度优先遍历方法描述为:从图中某个顶点v出发,在访问该顶点v之后,依次访问v的所有未被访问过的邻接点,然后再访问每个邻接点的邻接点,且访问顺序应保持先被访问的顶点其邻接点也优先被访问,直到图中的所有顶点都被访问为止。下面是对一个无向图进行广度优先遍历的过程。 下面我们讨论一下实现广度优先遍历算法需要考虑的几个问题:

(1)在广度优先遍历中,要求先被访问的顶点其邻接点也被优先访问,因此,必须对每个顶点的访问顺序进行记录,以便后面按此顺序访问各顶点的邻接点。应利用一个队列结构记录顶点访问顺序,就可以利用队列结构的操作特点,将访问的每个顶点入队,然后,再依次出队,并访问它们的诮拥悖 (2)在广度优先遍历过程中同深度优先遍历一样, 为了避免重复访问某个顶点,也需要创建一个一维数 组visited[0..n-1](n是图中顶点的数目),用来记录每 个顶点是否已经被访问过。

int visited[0..n-1]={0,0,...0}; void BFS(AdjList adj,int v) {//v是遍历起始点在邻接表中的下标,邻接表中下标从0开始 InitQueue(Q); //Q是队列 visited[v]=1; visite(adj[v].item); EnQueue(Q,v); while (!QueueEmpty(Q)) { DeQueue(Q,v); for (w=adj[v].firstedge;w;w=w->next) if (!visited[w->adjvex]) { visited[w->adjvex]=1; visite(adj[w->adjvex].item); EnQueue(Q,w->adjvex); } }

6.4 最小生成树问题 6.4.1 图的生成树和森林 对于一个拥有n个顶点的无向连通图,它的边数一定多余n-1条。若从中选择n-1条边,使得无向图仍然连通,则由n个顶点及这 n-1条边(弧)组成的图被称为原无向图的生成树。显示了一个无向连通图的生成树,双线圈表示的顶点为生成树的根结点。

图 6-10

图 6-11

图 6-12

图 6-13

6.4.2 最小生成树 在一个图中,每条边或弧可以拥有一个与之相关的数值,我们将它称为权。这些权可以具有一定的含义,比如,表示一个顶点到达另一个顶点的距离、所花费的时间、线路的造价等等。这种带权的图通常被称作网。 图或网的生成树不是唯一的,从不同的顶点出发可以生成不同的生成树,但n个结点的生成树一定有n-1条边。

图 6-14

图 6-15

下面我们计算一下上面两棵生成树的权值之和。第一棵生成树的权值总和是:16+11+5+6+18=56;第二棵生成树的权值是:16+19+33+18+6=92。通常我们将权值总和最小的生成树称为最小生成树。 构造最小生成树的方法:最初生成树为空,即没有 一个结点和一条边,首先选择一个顶点作为生成树的根, 然后每次从不在生成树中的边中选择一条权值尽可能小 的边,为了保证加入到生成树中的边不会造成回路,与 该边邻接的两个顶点必须一个已经在生成树中,

一个则不在生成树中,若网中有n个顶点(这里考虑的网是一个连通无向图),则按这种条件选择n-1边就可以得到这个网的最小生成树了。详细的过程可以描述为:设置2个集合,U集合中的元素是在生成树中的结点,V-U集合中的元素是不在生成树中的顶点。首先选择一个作为生成树根结点的顶点,并将它放入U集合,然后在那些一端顶点在U集合中,而另一端顶点在V-U集合中的边中找一条权最小的边,并把这条边和那个不在U集合中的顶点加入到生成树中,即输出这条边,然后将其顶点添加到U集合中,重复这个操作n-1次。

下面我们考虑一下如何实现这个操作过程的算法。 分析 :(1)它主要有两项操作:按条件选择一条边和将顶点加入到U集合中;(2)网中的每个顶点不是在U集合中,就是在V-U集合中。为了提高算法的时间、空间效率,我们将为这个算法设计一个辅助数组closedge,用来记录从集合U到集合V-U具有最小权值的边。对每个属于V-U集合的顶点,在辅助数组中存在一个相应的分量closedge[i-1],它包括两个域,一个域用来表示在该顶点与V-U集合中某些顶点构成的边中权最小的那条边的权值,若该顶点进入U集合,则值为0;另一个域表示这条最小权值的边对应的在V-U集合中的顶点下标。其类型定义如下所示:

#define MAX_NUM 10 struct { int adjvex; float lowcist; }closedge[MAX_NUM]; 整个算法的执行过程可以描述为: { 初始化closedge数组的内容; 选择某个顶点k作为生成树的根结点,并将它加入到U集 合中;重复下列操作n-1次: 选择一条满足条件的边; 输出这条边的两个端点; 修改V-U集合中的顶点信息,即与U集合中构成最小权值的边。 }

假设该网以邻接矩阵的形式给出,则完整的算法为: void Mini_SpanTree(Graph G,int k,int n) {//G是网的邻接矩阵,k是生成树根结点的序号,n是网的顶点数目 for (j=0;j<n;j++) if (j!=k) closedge[j]={k,G[k][j]}; closedge[k].lowcost=0;

for (i=1;i<n;i++) { k=minmun(closedge); printf(k,closedge[k].adjvex); closedge[k].lowcost=0; //将顶点加入U集合中 for (j=0;j<n;j++) if (closedge[i]&&G[k][j]<closedge[j].lowcost) closedge[j]={k,G[k][j]}; }

6.5 拓扑排序问题 拓扑排序是有向图的一个重要操作。在给定的有向图G中,若顶点序列vi1,vi2,...,vin满足下列条件:若在有向图G中从顶点vi到顶点vj有一条路径,则在序列中顶点vi必在顶点vj之前,便称这个序列为一个拓扑序列。求一个有向图拓扑序列的过程称为拓扑排序。 举例:计算机专业的学生应该学习的部分课程及其每门课程所需要的先修课程。

图 6-16

拓扑排序的方法: (1)从图中选择一个入度为0的顶点且输出之; (2)从图中删掉该顶点及其所有以该顶点为弧尾的弧; 反复执行这两个步骤,直到所有的顶点都被输出,输出的序列就是这个无环有向图的拓扑序列。细心的读者可能会发现:在每一时刻,可能同时存在多个入度为0的顶点,选择注:表中c1~c9列表示的是每个顶点的入度。 下面我们讨论一下如何实现拓扑排序的算法。假设有向图以邻接表的形式存储。 下面给出算法实现的基本过程:

{ 将所有入度为0的顶点入栈; 当栈非空时重复执行下列操作: 从栈中退出顶点k; (1)将k顶点的信息输出; (2)将与k邻接的所有顶点的入度减1。 }

#define MAX_VERTEX_NUM 30 //最大顶点个数 type struct EdgeNode{ //边结点 int adjvex; struct EdgeNode *next; }EdgeNode; typedef struct VexNode{ //顶点结点 EntryType item; int indegree; //记录顶点的入度 EdgeNode *firstedge; }VexNode,AdjList[MAX_VERTEX_NUM];

下面是拓扑排序的完整算法。 Status TopologicalSort(AdjList adj) { InitStack(s); for (i=0;i<MAX_VERTEX_NUM-1;i++) if (adj[i].indegree==0) Push(s,i); while (!StackEmpty(s)) { Pop(s,i); printf(i); for (p=adj[i].firstedge;p;p=p->next) { adj[i].indegree-=1; if (adj[i].indegree==0) Push(s,i); }