图论基础

一、图的初识

在一个社交网络中,每个帐号和他们之间的关系构成了一张巨大的网络,就像下面这张图:

image.png

那么在电脑中,我们要用什么样的数据结构来保存这个网络呢?这个网络需要用一个之前课程里未提到过的数据结构,也就是接下来要讲解的 结构来保存。

到底什么是图?图是由一系列顶点和若干连结顶点集合内两个顶点的边组成的数据结构。数学意义上的图,指的是由一系列点与边构成的集合,这里我们只考虑有限集。通常我们用 G = (V, E) 表示一个图结构,其中 V 表示点集,E 表示边集。

在顶点集合所包含的若干个顶点之间,可能存在着某种两两关系——如果某两个点之间的确存在这样的关系的话,我们就在这两个点之间连边,这样就得到了边集的一个成员,也就是一条边。对应到社交网络中,顶点就是网络中的用户,边就是用户之间的好友关系。

如果用边来表示好友关系的话,对于微信这种双向关注的社交网络没有问题,但是对于微博这种单向关注的要如何表示呢?

于是引出了两个新的概念:有向边无向边

1.1 有向边无向边

简而言之,一条有向边必然是从一个点指向另一个点,而相反方向的边在有向图中则不一定存在;而有的时候我们并不在意构成一条边的两个顶点具体谁先谁后,这样得到的一条边就是无向边。就像在微信中,AB 的好友,那 B 也一定是 A 的好友,而在微博中,A 关注 B 并不意味着 B 也一定关注 A

对于图而言,如果图中所有边都是无向边,则称为无向图,反之称为有向图。

简而言之,无向图中的边是“好友”,而有向图中的边是“关注”。一般而言,我们在数据结构中所讨论的图都是有向图,因为有向图相比无向图更具有代表性。实际上,无向图可以由有向图来表示。如果 AB 两个点之间存在无向边的话,那用有向图也可以表示为 AB 两点之间同时存在 ABBA 两条有向边。仍然以社交网络举例:虽然微博中并不存在明确定义的好友关系,但是一般情况下,如果你和另一个 ID 互相关注的话,那么我们也可以近似认为,你和 TA 是好友。

1.2 图的准确定义

我们来形式化地定义一下图:图是由顶点集合(简称 点集)和顶点间的边(简称 边集)组成的数据结构,通常用 G(V, E) 来表示。其中点集用 V(G) 来表示,边集用 E(G) 来表示。在 无向图 中,边连接的两个顶点是无序的,这些边被称为 无向边。例如下面这个无向图 G,其点集 V(G)=\{1,2,3,5,6\},边集为 E(G)=\{(1,2),(2,3),(1,5),(2,6),(5,6)\}

image.png

而在有向图中,边连接的两个顶点之间是有序的。箭头的方向就表示有向边的方向。例如下面这张有向图 G'

image.png

其点集 V(G')=\{1,2,3,5,6\},边集为 E(G')=\{(1,2),(2,3),(2,6),(6,5),(1,5)\}。对于每条边 (u,v),我们称其为从 uv 的一条有向边,u 是这条有向边的 起点v 是这条有向边的 终点。注意在有向图中,(u,v)(v,u) 是不同的两条有向边。

二、图的特征

2.1 图的分类

有很少边或弧(如 e < n\log ne 指边数,n 指顶点数)的图称为 稀疏图,反之称为 稠密图。对应到微博里,如果在一个圈内,同学们都互相关注,则我们可以认为该关系图是一个稠密图,如果只有几个人关注了别人,则我们可以认为这是一个稀疏图。如果图中边集为空,则称该图为 零图

如果无向图中任何一对顶点之间都有一条边相连,也就是有 \frac{n \times (n - 1)}{2} 条不重复的边,则这个无向图被称为 完全图。类似地,如果有向图中任何一对顶点 u,v 之间都有两条有向边 (u,v), (v, u) 相连,则称这个有向图为 有向完全图。下图就是由 4 个顶点组成的无向完全图。

image.png

对于一个图,如果以任意一个点为起点,在图上沿着边走都可以到达其他所有点(有向图必须沿有向边的方向),那么这个图就是连通图。显然完全图一定是连通图。

2.2 度的概念

在无向图中,顶点的 是指某个顶点连出的边数。例如在下图中,顶点 b 的度数为 3,顶点 a 的度数为 4

image.png

在有向图中,和度对应的是 入度出度 这两个概念。顶点的入度是指以该顶点为终点的有向边数量;顶点的出度是指以顶点为起点的有向边数量。需要注意的是,在有向图里,顶点是没有 的概念的。例如在下图中,顶点 a 的入度为 1,出度为 3;顶点 c 的入度为 2,出度为 2

image.png

2.3 度的性质

在无向图或有向图中,顶点的度数总和为边数的两倍,即:
|E|=\frac{1}{2}\sum_{i=1}^n deg(u_i)
而在有向图中,有一个很明显的性质就是,所有顶点的入度和等于出度和

三、邻接矩阵

这一节我们来学习的图的一种储存方式——邻接矩阵

3.1 邻接矩阵与图

什么是邻接矩阵呢?所谓邻接矩阵存储结构就每个顶点用一个一维数组存储边的信息,这样所有点合起来就是用矩阵表示图中各顶点之间的邻接关系。所谓矩阵其实就是二维数组。

对于有 n 个顶点的图 G = (V, E) 来说,我们可以用一个 n \times n 的矩阵 A 来表示 G 中各顶点的相邻关系,如果 v_iv_j 之间存在边(或弧),则 A[i][j] = 1,否则 A[i][j] = 0。下图为有向图 G_1 和无向图 G_2 对应的邻接矩阵:

image.png

image.png

image.png

image.png

一个图的邻接矩阵是唯一的,矩阵的大小只与顶点个数 N 有关,是一个 N \times N 的矩阵。前面我们已经介绍过,在无向图里,如果顶点 v_iv_j 之间有边,则可认为顶点 v_iv_j 有边,顶点 v_jv_i 也有边。对应到邻接矩阵里,则有 A[i][j] = A[j][i] = 1。因此我们可以发现,无向图的邻接矩阵是一个对称矩阵。

在邻接矩阵上,我们可以直观地看出两个顶点之间是否有边(或弧),并且很容易求出每个顶点的度,入度和出度。

这里我们以 G_1 为例,演示下如何利用邻接矩阵计算顶点的入度和出度。顶点的出度,即为邻接矩阵上点对应行上所有值的总和,比如顶点 1 出度即为 0 + 1 + 1 + 1 = 3;而每个点的入度即为点对应列上所有值的总和,比如顶点 3 对应的入度即为 1 + 0 + 0 + 1 = 2

image.png
image.png

接下来我们就先一起学习构造和使用邻接矩阵的方法。邻接矩阵是一个由 10 构成的矩阵。处于第 i 行、第 j 列上的元素 10 分别代表顶点 ij 之间存在或不存在一条有向边。

显然在构造邻接矩阵的时候,我们需要实现一个整型的二维数组。由于当前的图还是空的,因此我们还要把这个二维数组中的每个元素都初始化为 0

在构造好了一个图的结构后,我们需要把图中各边的情况对应在邻接矩阵上。实际上,这一步的实现非常简单,当从顶点 xy 上存在边时,我们只要把二维数组对应的位置置为 1 就好了。

image.png

用邻接矩阵来构建图需要如下几步,我们可以用二维数组G来表示一个图。

3.2 初始化

初始化的过程很简单,只需要把数组初始化为 0 即可。可以借助memset来快速地将一个数组中的所有元素都初始化为 0

memset(G, 0, sizeof(G));

注意,memset只能用来初始化 0-1,并且需要加上头文件cstring

上面的代码等价于:

for (int i = 0; i < N1; i++) { // N1 为数组第一维大小
    for (int j = 0; j < N2; j++) { // N2 为数组第二维大小
        G[i][j] = 0;
    }
}

当然我们平常使用邻接矩阵的时候下标只用 1n 或者 0n - 1 (这个看题目中点的编号)。

3.3 邻接矩阵元素的修改

插入边

如果插入一条无向边 (u,v),只需要

G[u][v] = 1;
G[v][u] = 1;

也可以写成G[u][v] = G[v][u] = 1;

如果插入一条有向边 (u,v),只需要G[u][v] = 1;

访问边

如果G[u][v] = 1,说明有一条从 uv 的边,否则没有从 uv 的边。

3.4 带权值的图

在前面的课程中,图中的边都只是用来表示两个点之间是否存在关系,而没有体现出两个点之间关系的强弱。比如在社交网络中,不能单纯地用 01 来表示两个人否为朋友。当两个人是朋友时,有可能是很好的朋友,也有可能是一般的朋友,还有可能是不熟悉的朋友。

我们用一个数值来表示两个人之间的朋友关系强弱,两个人的朋友关系越强,对应的值就越大。而这个值就是两个人在图中对应的边的权值,简称 边权。对应的图我们称之为 带权图

如下就是一个带权图,我们把每条边对应的边权标记在边上:

image.png

带权图也分成带权有向图和带权无向图。前面学到的关于图的性质在带权图上同样成立。实际上,我们前面学习的图是一种特殊带权图,只不过图中所有边的权值只有 1 一种;而在带权图中,边的权值可以是任意的。

用邻接矩阵存储带权图和之前的方法一样,用G[a][b]来表示 ab 之间的边权(我们需要用一个数值来表示边不存在,如0)。同样,对于无向图,这个矩阵依然是对称的。

image.png
image.png

如上所示,左边的图对应的右边的邻接矩阵。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 图论基础 1、图的定义 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其...
    jqboooo阅读 292评论 0 0
  • 概念 图是由顶点V和边E的集合组成的二元组,记G=(V,E) 有向图、无向图、有权图、无权图、连通图(联通分量)、...
    欧文坐公交阅读 733评论 0 0
  • 图论基础(Graph Theory) 图是由结点(Vertex)和边(Edge)组成的抽象的数据结构。结点和结点之...
    李威威阅读 544评论 0 1
  • 图分为有向图,和无向图。 如果图的边数接近顶点数其为稠密图 如果图的边数远远小于顶点数其为稀疏图 表示稠密图一般采...
    一个人的飘阅读 495评论 0 0
  • 图的表示有两种: 邻接矩阵(Adjacency Matrix)和邻接表(Adjacency Lists) 1、邻接...
    滨岩阅读 160评论 0 0