赞
踩
概述
上一篇文章将图相关的常见概念大概讲了一遍,今天主要介绍图相关的算法,可能一下子不太能理解,我会尽量用大白话为大家讲解,请耐心将不是很明白的地方多看几遍。如果有不正确的地方,还请指出,一起进步。
下面,我们将开始正文
拓扑排序究竟是啥?
在了解拓扑排序之前,首先需要知道AOV网(Activity On Vertex Network)
,它长成下面这样:
在AVO网中,顶点表示活动(Activity),边用来表示活动之间的先后顺序。不难看出,AOV网是一种有向无环图。
AOE网
与AOV网不同的是每条边都有权值,可以理解为完成某个活动的开销,例如,在上面的AOV网中,如果给每个边加上权值,那么就可以表示花费的时间
拓扑排序
在上面那个AOV网中,所有活动之间的关系都通过边表示出来了,如何把这些事情有条不紊的做完对你来说肯定都可以看出来,比如:去菜市场 --> 买菜 --> 买米 --> 做饭 --> 做菜 -->吃饭,这种顺序其实就是拓扑排序
,并且也很容易发现的是,对于同一个AOV网拓扑排序的结果可能有多个。
但是,倘若这个AOV网有上百个活动,活动之间的先后顺序也错综复杂,此时我们想按照一定的顺序将如此多的事情做完并且也符合活动的先后顺序,此时就不能用肉眼去观察了,那样太费时间了,因此,就出现了拓扑排序算法
,那么它是如何实现的呢?让我们先来分析一下我们之前的那个拓扑排序你就明白了,让我们来观察一下下图:
不知道你通过上图拓扑排序生成的过程是否发现了其中的规律:
没有被其他活动所指向的活动
(也就是入度
为0的点)恭喜你,你已经学会了拓扑排序了!下面就是拓扑排序的部分代码:
/** * 拓扑排序——(可用来判断有向图中是否有环) * * @return */ @Override public List<V> topologicalSort() { // 记录遍历过的节点,也即拓扑排序的结果 List<V> list = new ArrayList<>(); // 队列 Queue<Vertex<V, E>> queue = new LinkedList(); // map映射,记录顶点的入度信息 Map<Vertex<V, E>, Integer> map = new HashMap<>(); // 初始化队列和map vertices.forEach((v, vertex) -> { // 入度 int in = vertex.inEdges.size(); // 将一开始入度为0的顶点放入队列,不为0的放入map中 if (in == 0) { queue.offer(vertex); } else { map.put(vertex, in); } }); while (!queue.isEmpty()) { Vertex<V, E> vertex = queue.poll(); list.add(vertex.value); // 更新它所指向的顶点的入度 for (Edge<V, E> edge : vertex.outEdges) { // 顶点更新后的入度 int in = map.get(edge.to) - 1; if (in == 0) { // 放入队列中 queue.offer(edge.to); } else { // 更新map中该顶点对应的入度 map.put(edge.to, in); } } } return list; }
不知道,你有没有注意到我在方法上所写的注释信息:可用来判断有向图中是否有环,这怎么理解呢?
来看看下面的这张图你应该就明白了:
如果你用之前拓扑排序的方法,就会发现,拓扑排序的结果只有E,也就是说,如果拓扑排序的活动数量小于原先AOV网中活动的数量时,就表明有向图中存在环!
至此,就是拓扑排序的全部内容了!
kruskal(克鲁斯卡尔)算法与prim(普里姆)算法
什么是生成树?
对于连通图(图中任意两点直接都是连通的)来说,如果可以用其中最少的边来表示的连通图,就是这个连通图的最小生成树,下面是示例:
Prim(普里姆)算法
该算法,用到了集合的思想,首先让 E点 属于集合一,然后其余点属于集合二,然后选择一条连接集合一与集合二的边,并将被选择边所连接的原属于集合二的点加入到集合一中,然后再重复上述步骤选择一条边,直至集合二中没有点为止,这么一听是不是有点蒙,话不多说,直接上图:
上面为了简单起见,所演示的是无向边且没有权值的,所以每次对边的选择都是随机的,但如果是在有权值的AOE网中,那么久需要每次选择全职最小的即可得到最小生成树了
Kruskal(克鲁斯卡尔)算法
该算法步骤比较简单,即按照权值的大小,每次选择一条权值最小的边即可,并且,会在选择之前进行判断——选择该条边之后是否会形成环,如果会形成环则舍弃,不会形成环就选择,直至边的数量比顶点的数量少1为止。怎么样是不是很简单?来看看步骤是怎么样的:
说明:
边的数量 = 定点数 - 1
,算法结束
至此,你已经学会了拓扑排序、Prim算法和Kruskal算法了!怎么样,是不是觉得图相关的算法那其实并不难。限于时间,这次更新的内容就这么多,之后会更新Dijkstra算法和Bellman-Ford算法。今天的内容如果有错误的地方还望指出,共同进步。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。