-
宽度优先遍历,bfs,只需要Node即可,不需要edge
- 一个队列,一个set,set为queue服务,已经进过队列的点不会再进队列
- 入队之前检查是否在set里,入队的同时入set
-
在很经常的情况下,点集合的哈希表结构可以简化成数组结构
- 在常数级上进行优化
- 原因是通常点的value值就是一个整形编号可以作为下标
- 而且范围通常不会特别大
-
深度优先遍历,dfs,用栈来实现
- 一个栈,一个set
- 与bfs不同,深度优先遍历是加到栈里的时候就要进行处理,bfs是出队的时候才进行处理
- 比宽度优先遍历更加复杂
- 从栈中弹出
- 遍历他的nexts
- 如果还有不在set中的next
- 将当前点压回栈中
- 将这个next压到栈顶,加入set并处理
- break回到第一步
- 直到栈为空
- 即是
- 处理完当前的点之后,或者是下方处理完返回到这一层之后
- 会检查他的所有邻居
- 有路没有走过就往下走走到无路可走,否则继续往上返回
-
拓扑排序算法
- 适用条件:有向无环图, 没有循环依赖
- 首先看入度为0,一定是排在最前面的A
- 将A及他的影响擦掉,找下一个入度为0的点
- 编程实现
- 一张哈希表inMap,key是Node,value是这个点当前剩余的入度
- 一个队列,入度为0的点入队
- 记录初始inmap,入度为0入对
- 出队,加入链表结果数组
- 所有的next,在inmap中入度-1
- 新的入度为0的点加入队列
-
kruskal算法(ElogE)
-
要求:无向图
-
从边的角度出发,先把所有的边排序,每次选最小的边
-
每一次只需要考察加入当前边之后会不会形成环
-
需要并查集结构
-
一开始所有的点的集合都只有自己,所有的点都不连通
-
考察某一条边的时候,考察from和to所在的集合是否是同一个集合
- 是,不可用,会形成环,看下一条更大的边
- 不是,可以用,from和to的集合要合并
-
并查集实现快,查询和合并都是常数级别,先用一个比较慢的实现(合并不是常数集)
public static class MySets{ public HashMap<Node, List<Node>> setMap; public MySets(List<Node> nodes) { for(Node cur : nodes) { List<Node> Set = new ArrayList<Node>(); set.add(cur); setMap.put(cur, set); } } public boolean isSameSet(Node from, Node to) { List<Node> fromSet = setMap.get(from); List<Node> toSet = setMap.get(to); return fromSet == toSet; } public void union(Node from, Node to) { List<Node> fromSet = setMap.get(from); List<Node> toSet = setMap.get(to); for(Node toNode : toSet) { fromSet.add(toNode); setMap.put(toNode, fromSet); } } }
-
-
定义一个比较器,自己做一个堆,优雅的每次弹出最小的边
-
-
prim算法,同样要求是无向图(VLogE)
- 一开始所有的边都没有被解锁
- 选择一个点之后,相关的边被解锁
- 从所有被解锁没有被选过的边中调一个最小的边
- 一定要能够拽进一个新的点(边中一个点不在哈希表set中),产生新的解锁边
- k算法需要一个集合的查询和合并,因为有已经连成两片的东西连在一起
- 而p算法只需要一个哈希表,因为点是一个个加到哈希表中的
- 编程实现
- 所有解锁的边放入小根堆
- 一个hashset检查两个点是否都已经在里面
- set.add
- priorityQueue.add
- if(!set.contains)
- 这个代码会重复放入边,进优先队列,但是不影响结果,增加了一点常数时间
- 要注意处理森林的问题,不连通的图,可能各自要生成最小生成树
-
dijkstra算法,单源最短路径算法(没有权值为负的边)
-
一定要规定出发点,算出到所有其它点的最短距离
-
有一种启发式算法A*,比dijkstra效率更好
-
初始化如下的记录表
-
每次从记录表中挑一个最小的进行处理
-
查看这个点向外发散的所有边,看能否使其他点的距离更新变小
-
如果能则更新,使用所有边之后,当前点的记录就固定了
-
继续挑最小的进行处理
-
如果有权值为负的边,可能某一时刻,某一个锁定的点结论就不对了
-
其实完整的条件是不能有累加和权值为负数的环,可以有权值为负的边
-
dijkstra也有一个改进方法,需要一个自己改进的堆
-
最基础的是,每一次都遍历选出一个最小的点
-
貌似可以用堆,但是某一个较大的值突然变小,堆里的东西就需要修改
-
系统实现的堆不能临时改完然后修改让堆进行修改,只能自己手动实现堆
-
用pq优化后复杂度mlogn,原复杂度n^2
bellmanford算法,有负边查找最短路,查找负环,复杂度mn
floyd算法,查找所有点对最短路