博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
图总结
阅读量:4089 次
发布时间:2019-05-25

本文共 3173 字,大约阅读时间需要 10 分钟。

在求职和面试中,图也是很重要的一个领域。而这里面尤其重要的是深度优先搜索、广度优先搜索、最小生成树、最短路径、拓补排序、有向图的连通性的内容。在这里,我们只抽象地对图及各种算法进行分析,尽量不涉及代码实现。

(参考:《Java数据结构和算法》)

我们首先明确图的定义。在这里,我们讨论的都是连通图,也就是至少有一条路径可以连通所有顶点。有一种情况是有些路径只能有一个方向,称为有向图。有些图边被赋予一个权值,叫带权图。

一、无向图:深度优先搜索、广度优先搜索、最小生成树

DFS和BFS都可以用递归和非递归来实现,但是逻辑都是一样的,而且非递归还更好理解。关键是要理解其决策树以及使用栈和队列的思想,在具体的应用场景中再用代码实现。

1、深度优先搜索(DFS)

(1)算法步骤

图的顶点要设置一个标志位,来表示是否已经被访问过。如果访问过的顶点,该顶点会被置位标志位。DFS通过栈来实现。它的算法步骤如下:

把图中某个顶点作为起点。先访问该顶点,标记他,然后把该顶点放入栈中;

while(栈不为空){

    if(栈顶的顶点还有没访问过的邻接顶点){

        访问栈顶的顶点的某个邻接的顶点,标记他,然后把该顶点放入栈中;

    }

    else{

        把栈顶的顶点出栈;

    }

}

可以看出,要自己定一个有规律的,访问某顶点的邻接顶点的顺序。深度优先搜索要得到距离起始点最远的顶点,然后在不能继续前进的时候返回。

(2)应用

深度优先搜索经常被用于游戏仿真中(或者现实世界中与游戏相似的情况)。在一般游戏中,可以在几个可能的动作中选择一个,每个选择导致更进一步的选择,这些选择又产生了更多的选择,这样就形成了一个代表可能性不断延伸的树形图。这就是决策树。

2、广度优先搜索,也叫宽度优先搜索(BFS)

BFS要使用队列,而不是栈。它跟DFS不同,它首先访问起始顶点的所有邻接顶点,然后再访问较远的区域。

(1)算法步骤

把图中某个顶点作为起点。先访问该顶点,标记他,然后把该顶点放入队列中;

while(队列不为空){

    if(队列头顶点还有没访问过的邻接顶点){

        访问队列头顶点的某个邻接的顶点,标记他,然后把该顶点放入队列中;

    }

    else{

        把队列头的顶点出队列;

    }

}

(2)应用

BFS首先找到与起始点相距一条边的所有顶点,然后是相距两条边的顶点,以此类推。如果要寻找起始顶点与指定顶点的最短距离,那这个属性非常有用。首先执行BFS,当找到指定顶点时,就可以说这条路径是到这个顶点的最短路径。

3、最小生成树(MST)

最小生成树,也就是把一个图多余的边去掉,生成一种图,他用最少的边连接了所有的顶点。对于某一个图来说,最小生成树并不是唯一的。此时他的边的数量一定是他的顶点的数量减一。此时,我们还不需要考虑边的权值以及方向。创建最小生成树的算法和DFS,BFS几乎是一样的,所不同的是每次读取顶点同时,要记住已经走过的边。其实用DFS生成的天然就是一个最小生成树。用DFS生成最小生成树比BFS简单多了。用DFS访问定点,它返回的定点的顺序就是一个最小生成树。只需要一个个返回顶点,然后把路径记录下来即可。

二、有向图:拓补排序、有向图的连通性

若图有方向的情况下,称为有向图。有向图在实际中有很重要的应用,例如在大学的课程选修中,经常听到上某门课的前提是修了另一门课的学分。为了拿到学位,要上高级研讨会,而只有先后上了代数和高等数学,才能上高级研讨会。

假设存在一个列表,包含了要得到学位所必修的全部课程,我们按课程的先后顺序排列它,可以得到以下这个序列:

BAEDGCFH

这种方法的排列,称为图的拓补排序。造出拓扑序列的实际意义是:如果按照拓扑序列中的顶点次序,在开始每一项活动时,能够保证它的所有前驱活动都已完成,从而使整个工程顺序进行,不会出现冲突的情况。但是注意:

(1)拓补排序不是唯一的;(2)他可以用于连通图,也可以用于非连通图;(3)有环图拓补排序是无法处理的。事实上,不包含环的图就是树。拓补排序必须在无环的有向图中处理。

1、拓补排序的算法如下:

(1)找到一个没有后继的顶点;

(2)把它放入数组中,并且从图中删除顶点以及连接到它的边;

(3)不断进行(1)和(2),如果找不到没有后继的顶点了,但是数组中的顶点数量还没达到图的顶点数量,说明图中必然存在环。

2、有向图的连通性

从前面得知,在无向图中,利用深度优先和广度优先搜索可以找到所有相互连通的点。而对有向图来说,就有点麻烦了。因为不能从任意一个顶点开始,期望找到所有其他连通的顶点,因为图是有方向的。关于有向图连通性的问题主要是,如果从一个指定顶点出发,能够到达哪些顶点?

(1)连通性表

连通性表,其实就是一张表,对于这个表上的所有顶点,从这个顶点能到达图中哪个顶点。

例如,对于这个有向图,AC, BACE, C, DEC, EC就是他的连通性表。第一个字母是起始点,接下来的字母是能够到达的顶点(直接或间接)。得到这个连通性表的方法很简单,就是对每一个顶点使用DFS即可。

(2)

对于有向图的连通性,还有一个问题:一个顶点,是否可以从另外一个顶点可以到达?对于这个问题,可以查看连通性表,但是这需要查看连通性表的某行所有表项,需要O(N)的时间复杂度。能否有一个更好的算法,可以在O(1)时间复杂度里,告知一个顶点对另一个顶点是否可以到达?这就需要使用Warshall算法。事实上,它的本质就是动态规划。

三、带权图:带权图的最小生成树、最短路径问题

1、带权图的最小生成树

其实就是找到一棵最小生成树,连接所有顶点,权值最小。要注意,最小生成树也不一定是唯一的。这在现实生活中有很大的意义,例如光纤布线等。要实现这个算法需要使用优先级队列。这里要注意两个问题:

(1)连通n个顶点,需要n-1条边;(2)尽可能选取权值小的边,不能构成回路。

有以下两个算法(https://blog.csdn.net/luoshixian099/article/details/51908175):

(1)Prim算法

此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

  1. 图的所有顶点集合为VV;初始令集合u={
    s},v=Vu
    u={s},v=V−u
    ;
  2. 在两个集合u,vu,v能够组成的边中,选择一条代价最小的边(u0,v0)(u0,v0),加入到最小生成树中,并把v0v0并入到集合u中。
  3. 重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。

由于不断向集合u中加点,所以最小代价边必须同步更新;需要建立一个辅助数组closedge,用来维护集合v中每个顶点与集合u中最小代价边信息:

(2)Kruskal算法

此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。 
1. 把图中的所有边按代价从小到大排序; 
2. 把图中的n个顶点看成独立的n棵树组成的森林; 
3. 按权值从小到大选择边,所选的边连接的两个顶点ui,viui,vi,应属于两颗不同的树(为什么要有这个规定,是因为如果两个顶点属于不同的树,就不会形成环了),则成为最小生成树的一条边,并将这两颗树合并作为一颗树。 

4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。

在这里,边要先放入一个优先级队列里面,这样就可以拿到最小代价边。

2、最短路径问题

对于带权无向图来说,还有一个很重要的问题:给定两个顶点,如何找到一条路径,令两个顶点之间连通,而且权值最小呢?这里要用到Floyd算法。而如果是带权的有向图,要使用Dijkstra算法。

你可能感兴趣的文章
用STL algorithm轻松解决几道算法面试题
查看>>
ACfly之所以不怕炸机因为它觉得某个传感器数据不安全就立马不用了
查看>>
我发觉,不管是弄ROS OPENCV T265二次开发 SDK开发 caffe PX4 都是用的C++
查看>>
ROS的安装(包含文字和视频教程,我的ROS安装教程以这篇为准)
查看>>
国内有个码云,gitee
查看>>
原来我之前一直用的APM固件....现在很多东西明白了。
查看>>
realsense-ros里里程计相关代码
查看>>
似乎写个ROS功能包并不难,你会订阅话题发布话题,加点逻辑处理,就可以写一些基础的ROS功能包了。
查看>>
if __name__ == ‘__main__‘:就是Python里的main函数,脚本从这里开始执行,如果没有main函数则从上到下顺序执行。
查看>>
PX4官方用户和开发手册的首页面是会给你选择英文和中文的
查看>>
网络协议栈我是不是可以这么理解,就是把你要发送的数据自动处理成TCPIP格式的消息发出去,这种底层的转换不需要你弄了。
查看>>
除了LwIP还有uIP
查看>>
《跟工程师学嵌入式开发》这本书最后的终极项目我反而觉得有说头
查看>>
博士的申请考核制
查看>>
MAVLink学习之路05_MAVLink应用编程接口分析(也有讲STM32下的收发函数)
查看>>
找到了中文版的mavlink手册
查看>>
浅谈飞控开发的仿真功能
查看>>
我觉得在室内弄无人机开发装个防撞机架还是很有必要的,TBUS就做得很好。
查看>>
serial也是见到很多次了,似乎它就是一种串行通信协议
查看>>
TBUS的一些信息
查看>>