图的表示、深度广度遍历算法及其应用

世间的一切对象都可化为节点;世间一切关系都可化为节点间的一条线;从而组成了如梦幻泡影的图。将来的环球必定是图的世界。

一、图的表示

图有有向图和无向图,表示方法一般有邻接表、邻接矩阵等方法,无向图和有向图都可以用这两种方法表示。

图1. 图的例子[1]

1、邻接表

在邻接表中,对于每个顶点u,使用一个链表把所有与u相邻的点点串起来,并标记这个集合为adj(u)。举个栗子如下:

图2. 邻接表表示图的例子[1]

在真正操作图进行实验的时候,一般也都使用邻接矩阵表示,例如要存储图1中的有向图,可以直接用一个csv或者txt文件,存储内容如下:

5,14
1,3,2,5,4
2,3,1,5,3
3,2,2,4
4,3,1,5,3
5,3,4,1,2

上述文件就是第一行存储了总共的节点数量、边的数量;接下来的每一行就是此顶点的id和邻居的id,并且第2位数字存储了该节点总共有多少邻居节点;为了进一步的操作简单,可以把原有的节点id映射为从0到n,没有边的节点用0补充,此时行号和id相等了,访问起来更加迅速。这样存储的好处是需要较少的内存就可以完成,而且操作简单。

2、邻接矩阵

邻接矩阵顾名思义就是用一个n*n的矩阵,存储各节点之间的关系,空间复杂度$O(n^2)$,这样存储在一些矩阵运算的时候较为方便,例如转置。图1中两图的邻接矩阵如下:


图3. 邻接矩阵表示图的例子[1]

二、图周游算法

1、广度优先遍历

图的广度遍历顾名思义就是访问图中节点的时候,优先在广度上进行遍历;也就是访问到某节点A时,优先访问完A的所有邻居节点[节点的访问顺序并没有做要求,在具体的问题中此处可以定义访问顺序],再继续访问邻居的邻居,直接看代码:

#过程中主要是做三件事:颜色、距离、父节点
BFS(G(V,E),s)
    #初始化
    for each vertex u in V-{s}
        color[u] <- White
        d[u]<-∞
        pai[u]<-None
    endfor
    #处理开始节点
    color[s]<-Gray
    d[s]<-0
    pai[s]<-None

    #初始化队列
    Q<-Queue()
    Enqueue(Q,s)

    #开始广度访问图
    while not Q.empyt():
        u<-Dequeue(Q)
        for each v in Adj[u]:
            if color[v] = White #检查颜色是否为白色,即没有被访问过
                color[v] <- Gray #颜色,变颜色为灰色
                d[v]<-d[u]+1 #距离
                pai[v]<-u  #父节点
            endif
        endfor
    color[u]<-Black
    endwhile
    End    

应用:
无向图二着色问题,无奇回路<=>可以二着色<=>可以分为二部图

2、深度优先遍历

深度优先搜索是从某一顶点开始访问,然后访问他的邻居,与BFS不同的是,当深度优先搜索从某个顶点u访问他的邻居时,只选择其中的一个还未被访问的邻居v,然后暂时弃u的其他邻居于不顾,而从新的儿子节点v去访问v的邻居。当v出发的访问全部完成后,DFS回到u,然后再访问u的第二个邻居,以此类推。这里有个动画就好了,可是我不会画。
深度优先遍历,迭代方法的伪代码:

DFS(G(V,E))
    #初始化访问控制的颜色,父节点
    for each vetex u in V
        color[u] = White
        pai[u]=None
    endfor

    #最开始,时间为0
    time <- 0

    #对于每个节点进行一次深度优先遍历,防止图节点间不连通
    for each vetex u in V:
        if color[u]=While:
            then DFS-visit(u)
        endif
    endfor
    End
#对节点s,进行深度优先遍历
DFS-Visit(s):

    color[s] <- Gray
    time = time + 1
    d[s]<-time
    #如果访问到节点s的邻居节点,那么对其邻居节点迭代进行深度优先遍历
    for each v in Adj[s]:
        if color[v] = White
            pai[v]<-s
            DFS-Visit(v)
        endif
    endfor
    color[s]<-Black
    f[s]<-time<-time+1
    End

2.1 区间套定理:

2.2 白路径定理:

2.3 拓扑排序:

2.4 无回路有向图中最长路径问题:

一些应用问题需要找到图中的最短或者最长的简单路径(不含回路的路径),图往往是加权的。但是对于任意图,找一条最长路径是NPC问题,即使这个图是不加权的图。然而只有这个图是无回路的图时,不论是有向图还是无向图,加权还是不加权图,都可以在线性时间$O(|V|+|E|)=O(n+m)$。细心的我可能发现了,无回路的图就是棵树或者森林啊,两个顶点之间要么不连通,要不然就只有唯一的一条路径。

2.5 强连通分支:

定义1: 如果一个有向图中任意一顶点都有一条通向其他任一顶点的路径,那么这个有向图称为强连通图(strongly connected graph)
定义2: 有向图G,其隐含的无向图$G‘$是指把G中的每条边的方向都去掉后所得到的无向图。
定义3: 如果一个有向图G所隐含的无向图$G‘$是个连通图,那么有向图G称为弱连通图(weakly connected graph)
定义4: 如果一个有向图的子图是个强连通图,则成为强连通子图(strongly connected subgraph)
定义5: 如果一个有向图的强连通子图已最大,即不能在加入其他任何一个顶点而仍然强连通,那么这个子图称为强连通分支(strongly connected component)
这里强连通分支包含于强连通子图内。
定义6: 有向图的强连通分支问题就是把一个有向图的顶点划分为不相交的若干个强连通分支。

三、参考文献

[1] 沈孝钧. 计算机算法基础 : Essentials of computer algorithms[M]. 机械工业出版社, 2014.

原文地址:https://www.cnblogs.com/datasnail/p/9595517.html

时间: 2024-11-09 00:48:49

图的表示、深度广度遍历算法及其应用的相关文章

【数据结构-图】图的建立以及广度优先遍历算法

本文利用邻接表的方法将图进行了表示,并且利用广度优先遍历方法对图进行遍历 下面是一个图的示例: 代码如下: #include<iostream> using namespace std; typedef int VexType; typedef struct Arcnode{ VexType data; struct Arcnode *nextarc; }ArcNode; typedef struct Vexnode { VexType data; ArcNode *firstarc; }Vn

图的广度度优先遍历算法运用队列主针对邻接表有向图

源代码如下: #include<iostream> using namespace std; #define MAX_VERTEX_NUM 20 typedef int EdgeData; typedef char VertexData; //顶点数据域 typedef struct node { // 边表节点 EdgeData cost; //边上d权值 int adjvex; //邻接点域 struct node *next; //下一边链接指针 }EdgeNode; typedef s

8649 图的广度遍历

8649 图的广度遍历 时间限制:1000MS  内存限制:1000K提交次数:1573 通过次数:975 题型: 编程题   语言: G++;GCC Description 使用图的深度遍历实现的邻接表存储结构和基本操作函数,在此基础上实现图的广度遍历算法并加以测试.注意正确使用队列存储结构. 输入格式 第一行:输入0到3之间整数(有向图:0,有向网:1,无向图:2,无向网:3): 第二行:输入顶点数和边数: 第三行:输入各个顶点的值(字符型,长度〈3):(遍历从输入的第一个顶点开始) 第四行

数据结构-深度遍历和广度遍历(转)

本文转自http://blog.csdn.net/wingofeagle/article/details/13020373 深度遍历: 从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到. 其更适合:目标比较明确,以找到目标为主要目的的情况. 广度遍历: 类似于树中的层序遍历,首先遍历完和某一顶点v相连的所有顶点,然后再遍历和这些顶点相连的顶点,以此类推. 其更适合于:不断扩大遍历范围时找到相对最优解的情况. 具体代码如下:

(转)数据结构之图(存储结构、遍历)

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

图的存储结构及遍历

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

数据结构-6-深度广度遍历搜索原理详解

深度广度遍历搜索的定义想必大家都能熟练的掌握了,下面我就通过一个图的实例,把应用的代码直接贴上供大家参考,以后可以直接借鉴或者使用. #include <iostream> #include <string> #include "Queue.h" using namespace std; //图的邻接矩阵存储表示 #define INFINITY INT_MAX #define MAX_VERTEX_NUM 20 typedef enum {DG, DN, UD

图的广度遍历和深度遍历

/* 图的遍历方法主要有两种:一种是深度优先遍历,一种是广度优先遍历.图的深度优先遍历类同于树的先根遍历,图的广度遍历类同树的层次遍历 一:连通图的深度优先遍历算法 图的深度优先遍历算法是遍历时深度优先的算法,即在图的所有邻接顶点中,每次都在访问当前顶点后,首先访问当前顶点的第一个邻接顶点. 连通图的深度优先遍历递归算法如下: 1.访问顶点v并标记顶点v已访问. 2.查找顶点v的第一个邻接顶点w. 3.若顶点v的邻接顶点w存在,则继续执行,否则算法结束. 4.若顶点w尚未被访问,则深度优先遍历递

图的深度遍历和广度遍历

概述 图的遍历是指从图中的任一顶点出发,对图中的所有顶点访问一次且只访问一次.图的遍历操作和树的遍历操作功能相似.图的遍历是图的一种基本操作,图的其它算法如求解图的连通性问题,拓扑排序,求关键路径等都是建立在遍历算法的基础之上. 由于图结构本身的复杂性,所以图的遍历操作也较复杂,主要表现在以下四个方面:① 在图结构中,没有一个“自然”的首结点,图中任意一个顶点都可作为第一个被访问的结点.② 在非连通图中,从一个顶点出发,只能够访问它所在的连通分量上的所有顶点,因此,还需考虑如何选取下一个出发点以