图论算法(C++版)课件

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

• 建立邻接矩阵时,有两个小技巧:
• 初始化数组大可不必使用两重for循环。 • 1) 如果是int数组,采用memset(g, 0x7f, sizeof(g))可 全部初始化为一个很大的数(略小于0x7fffffff), • 使用memset(g, 0, sizeof(g)),全部清为0, • 使用memset(g, 0xaf, sizeof(g)),全部初始化为一个很 小的数。 • 2)如果是double数组,采用memset(g,127,sizeof(g));可 全部初始化为一个很大的数1.38*10306, • 使用memset(g, 0, sizeof(g))全部清为0.
第四章 图论算法
• 一对一和一对多的结构: • 在前边讲解的线性表中,每个元素之间只有一个直接前驱 和一个直接后继,在树形结构中,数据元素之间是层次关 系,并且每一层上的数据元素可能和下一层中多个元素相 关,但只能和上一层中一个元素相关。
• 图结构:是研究数据元素之间的多对多的关系。在这种
结构中,任意两个元素之间可能存在关系。即结点之间的 关系可以是任意的,图中任意元素之间都可能相关。 • 图的应用极为广泛,已渗入到诸如语言学、逻辑学、物理、 化学、电讯、计算机科学以及数学的其它分支。
对于带权值的网图,可以在边表结点定义中再 增加一个数据域来存储权值即可:
邻接表(网)
在进行邻接表的输入时,可以直接使用邻接表的定义方式直接输入; 也可由别的输入方式进行演变,课本上的就是利用边的顶点及其权值进行输入的
• 以下是用数组模拟邻接表存储的参考程序段:
const int N=maxn; // maxn表示图中最大顶 点数 const int E=maxe ; // maxe图中最大边数 struct Edge{ int u,v; //边所邻接的两个顶点 int w; //边的权值 int next; //边指针,指向下一条边的内存地址 }edge[E]; // 静态内存,用于分配边 int head[N]; // 表头 int num; // 内存的指针 void init() { for(int i=0;i<E;i++) head[i]=-1; //这里为什么 要设为-1 num= 0; } void addedge(int b,int e,int w) { edge[num].u=b; edge[num].v=e; edge[num].w=w; edge[num].next=head[b]; head[b]=num++; }
下图左侧并不是强连通图,右侧是。并且右侧是左侧的极 大强连通子图,也是左侧的强连通分量。
二、图的存储结构
图的存储结构比较复杂,其复杂性主要表现在: ◆ 任意顶点之间可能存在联系,无法以数据元素在存储区中 的物理位置来表示元素之间的关系。 ◆ 图中顶点的度不一样,有的可能相差很大,若按度数最大 的顶点设计结构,则会浪费很多存储单元,反之按每个顶点自 己的度设计不同的结构,又会影响操作。 图的常用的存储结构有:邻接矩阵、邻接链表、十字链 表、邻接多重表和边表。
基本思想:对图的每个顶点建立一个单链表,存储该顶点所有邻接顶点及其相关 信息。 每一个单链表设一个表头结点。 第i个单链表表示依附于顶点Vi的边(对有向图是以顶点Vi为头或尾的弧)。 图的邻接表存储法,又叫链式存储法。本来是要用链表实现的,但大多数情况下 只要用数组模拟即可。
• 邻接表(有向图) • 邻接表的处理方法是这样: • 图中顶点用一个一维数组存储,当然,顶点也可以用单链表 来存储,不过数组可以较容易地读取顶点信息,更加方便。 • 图中每个顶点Vi的所有邻接点构成一个线性表,由于邻接点 的个数不确定,所以我们选择用单链表来存储。
对于有向图G=(V,E),如果有<V1,V2>∈E,则称顶点V1邻接到 顶点V2,顶点V2邻接自顶点V1。 以顶点V为头的弧的数目称为V的入度(InDegree),记为ID(V), 以V为尾的弧的数目称为V的出度(OutDegree),记为OD(V), 因此顶点V的度为TD(V)=ID(V)+OD(V)。 下图顶点A的入度是2,出度是1,所以顶点A的度是3。
图的顶点与边之间的关系
• 对于无向图G=(V,E),如果边(V1,V2)∈E,则称顶点V1 和V2互为邻接点(Adjacent),即V1和V2相邻接。 • 边(V1,V2)依附(incident)于顶点V1和V2,或者说边 (V1,V2)与顶点V1和V2相关联。 • • 顶点V的度(Degree)是和V相关联的边的数目,记为 TD(V),如下图,顶点A与B互为邻接点,边(A,B)依附 于顶点A与B上,顶点A的度为3。
无向图中的极大连通子图称为连通分量。 注意以下概念: 首先要是子图,并且子图是要连通的; 连通子图含有极大顶点数; “极大”的含义:指的是对子 图再增加图G中的其它顶点,子图就不再连通。 具有极大顶点数的连通子图包含依附于这些顶点的所有边。
在有向图G中,如果对于每一对பைடு நூலகம்i到Vj都存在路径,则 称G是强连通图。 有向图中的极大强连通子图称为有向图的强连通分量。
图的各种定义
• 无向边:若顶点Vi到Vj之间的边没有方向,则 称这条边为无向边(Edge),用无序偶数对(Vi,Vj) 来表示。 • 无向图:图中所有顶点间的边均是无向的。
上图G1是一个无向图,G1={V1,E1},其中 V1={A,B,C,D}, E1={(A,B),(B,C),(C,D),(D,A),(A,C)}
• 1.二维数组邻接矩阵存储
• • •
基本思想:对于有n个顶点的图,用一维数组vexs[n]存储顶点信息,用二维数组
A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中,以顶点 在vexs数组中的下标代表顶点,邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关 系的信息。
•2.数组模拟邻接表存储 邻接矩阵看上去是个不错的选择,首先是容易理解,第二是索引和编排都很舒服 但是我们也发现,邻接矩阵适合于结点数较少的稠密图。如果用来表示稀疏图, 则会造成很大的空间浪费。 因此我们可以考虑另外一种存储结构方式,例如把数组与链表结合一起来存储, 这种方式在图结构也适用,我们称为邻接表(AdjacencyList)。
• • • • • • • • • • • • • •
int main() { num_edge=0; scanf("%d %d",&n,&m); //读入点数和边数 for(int i=1;i<=m;i++) { scanf("%d %d %d",&a,&b,&x); //a、b之间有一条长度为x的边 add_edge(a,b,x); } for(int i=head[1];i!=0;i=edge[i].next) //遍历从点1开始的所有边 { //... } //...
若是有向图,邻接 表结构就是这样定 义的。
有向图的邻接表: 我们先来看下把顶点当弧尾建立的邻接表,这样 很容易就可以得到每个顶点的出度:
但也有时为了便于确定顶点的入度或以顶点为弧头的弧,我们可以建立一个有向图 的逆邻接表:
此时我们很容易就可以算 出某个顶点的入度或出度 是多少,判断两顶点是否 存在弧也很容易实现。
无序对(A,B) 表示A和B之间的一条边(Edge),因此(A,B) 和(B,A)代表的是同一条边。
有向边:若从顶点Vi到Vj的边有方向,则称这条边为 有向边,也称为弧(Arc),用有序偶数对<Vi,Vj>来表 示,Vi称为弧尾,Vj称为弧头。 •有向图:图中所有顶点间的边均是有向的。
上图G2是一个无向图,G2={V2,E2},其中 V2={A,B,C,D}, E2={<B,A>,<B,C>,<C,A>,<A,D>}
右图用红线列举了从顶点B到顶 点D的四种不同路径:
如果G是有向图,则路径也是有向的。
下图用红线列举顶点B到顶点D的两种路径,而顶点A到顶点B就不存在路径。
路径的长度是路径上的边或弧的数目。 第一个顶点到最后一个顶点相同的路径称为回路或环(Cycle)。
连通图 在无向图G中,如果从顶点V1到顶点V2有路径,则称 V1和V2是连通的,如果对于图中任意两个顶点Vi和Vj 都是连通的,则称G是连通图(ConnectedGraph) 下图左侧不是连通图,右侧是连通图:
一、图的定义及其术语 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合 组成,通常表示为:G(V,E),其中,G表示一个图,V是图G 中顶点的集合,E是图G中边的集合。
• 对于图的定义,我们需要明确几个注意的地方: • 线性表中我们把数据元素叫元素,树中叫结点,在图中 数据元素我们则称之为顶点(Vertex)。 • 线性表可以没有数据元素,称为空表,树中可以没有结 点,叫做空树,而图结构在国内大部分的教材中强调顶 点集合V要有穷非空。 • 线性表中,相邻的数据元素之间具有线性关系,树结构 中,相邻两层的结点具有层次关系,而图结构中,任意 两个顶点之间都可能有关系,顶点之间的逻辑关系用边 来表示,边集可以是空的。
简单图:在图结构中,若不存在顶点到其自身的边,且同一条边不重复 出现,则称这样的图为简单图。以下两个则不属于简单图:
稀疏图、稠密图、权
有很少边或弧的图(e<n㏒n)的图称为稀疏图,反之称为稠密图。 权(Weight):与图的边和弧相关的数。权可以表示从一个顶点到 另一个顶点的距离或耗费。带权的图通常称为网(Network)。
无向完全图:在无向图中,如果任 意两个顶点之间都存在边,则称该 图为无向完全图。 含有n个顶点的无向完全图有 n*(n-1)/2条边。
有向完全图:在有向图中,如果 任意两个顶点之间都存在方向互 为相反的两条弧,则称该图为有 向完全图。 含有n个顶点的有向完全图有 n*(n-1)条边。
假设有两个图G1=(V1,E1)和G2=(V2,E2),如果 V2⊆V1,E2⊆E1,则称G2为G1的子图 (Subgraph)。
路径(Path)、路径长度、回路(Cycle) : 对无向图G=(V,E),若从顶点vi经过若干条边能到达vj, 称顶点vi和vj是连通的,又称顶点vi到vj有路径。
对有向图G=(V,E),从顶点vi到vj有有向路径,指的 是从顶点vi经过若干条有向边(弧)能到达vj。
在一条路径中,若没有重复相同的顶点,该路径称为简单 路径;第一个顶点和最后一个顶点相同的路径称为回路 (环);在一个回路中,若除第一个与最后一个顶点外,其 余顶点不重复出现的回路称为简单回路(简单环)。

• • • • • • • • • • • • • • • • • • • • •
下面是建立图的邻接矩阵的参考程序段:
#include<iostream> using namespace std; int i,j,k,e,n; double g[101][101]; double w; int main() { int i,j; for (i = 1; i <= n; i++) for (j = 1; j <= n; j++) g[i][j] = 0x7fffffff(赋一个超大值); //初始化,对于不带权的图g[i][j]=0,表示没有边 连通。这里用0x7fffffff代替无穷大。 cin >> e; for (k = 1; k <= e; k++) { cin >> i >> j >> w; // 读入两个顶点序号及权值 g[i][j] = w; //对于不带权的图g[i][j]=1 g[j][i] = w; //无向图的对称性,如果是有向图则不要有这句! } „„„„ return 0; }
定义int G[101][101]; G[i][j]的值,表示从点i到点j的边的权值,定义如下:
另外有向图是有讲究的,要考 虑入度和出度,顶点V1的入度 为1,正好是第V1列的各数之 和,顶点V1的出度为2,正好 是第V1行的各数之和。
上图中的3个图对应的邻接矩阵分别如下: 0 1 1 1 0 1 1 G(A)= 1 0 1 1 G(B)= 0 0 1 1 1 0 0 0 1 0 G(C)= 1 1 0 0 ∞ 5 8 ∞ 3 5 ∞ 2 ∞ 6 8 ∞ 3 2 ∞ 6 ∞ 10 4 10 ∞ 11 4 11 ∞
相关文档
最新文档