「这是我参与2022首次更文挑战的第40天,活动详情查看:2022首次更文挑战」。
一、什么是图的拓扑排序?
图的拓扑排序:根据先后顺序,能够一次把工作顺利做完,而且不缺依赖的一个顺序,所以就是所谓的拓扑序,不能出现循环依赖或环
对于拓扑排序一定是有向图,一定无环,即有向无环图,因为有环的话,就不知道是什么样的顺序了
拓扑排序不唯一
二、题目一
图的拓扑排序结果为2种: (A,D,E,F),(A,E,D,F)
1、分析
利用自定义图的in(入度)
A出去的时候,D和E的in减1
利用自定义图结构的入度(in),in为0代表指零个指向它的节点,按照这个原则实现图的拓扑排序
2、实现
// directed graph and no loop
public static List<Node> sortedTopology(Graph graph) {
// key 某个节点 value 剩余的入度
Map<Node, Integer> inMap = new HashMap<>();
// 只有剩余入度为0的点,才进入这个队列
Queue<Node> zeroInQueue = new LinkedList<>();
for (Node node : graph.nodes.values()) {
inMap.put(node, node.in);
if (node.in == 0) {
zeroInQueue.add(node);
}
}
List<Node> result = new ArrayList<>();
while (!zeroInQueue.isEmpty()) {
Node cur = zeroInQueue.poll();
result.add(cur);
for (Node next : cur.nexts) {
inMap.put(next, inMap.get(next) - 1);
if (inMap.get(next) == 0) {
zeroInQueue.add(next);
}
}
}
return result;
}
复制代码
三、题目二
1、分析
图的拓扑排序一定是有向无环图,可以利用点次大小从大到小排序
x->y->z
如果y点次90的话,x的点次一定大于90,所以如果x的点次>=y的点次,那么x一定在y的前边,也就是拓扑序这么排没问题
假如x点从自己往后走一遍,点次算一遍,得出x点次,y往后走一遍,算一遍点次,或者 a从自己出发也的算一遍,这算的过程,之前有算过,意思就是走过的路,能不能记录下来,等到用到的时候,直接拿结果,岂不是快哉,可以用记忆化缓存来记录,提升效率
记忆化搜索(记忆化缓存 或 杀缓存)
2、实现
2.1、方法一
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
HashMap<DirectedGraphNode, Integer> indegreeMap = new HashMap<>();
for (DirectedGraphNode cur : graph) {
indegreeMap.put(cur, 0);
}
for (DirectedGraphNode cur : graph) {
for (DirectedGraphNode next : cur.neighbors) {
indegreeMap.put(next, indegreeMap.get(next) + 1);
}
}
Queue<DirectedGraphNode> zeroQueue = new LinkedList<>();
for (DirectedGraphNode cur : indegreeMap.keySet()) {
if (indegreeMap.get(cur) == 0) {
zeroQueue.add(cur);
}
}
ArrayList<DirectedGraphNode> ans = new ArrayList<>();
while (!zeroQueue.isEmpty()) {
DirectedGraphNode cur = zeroQueue.poll();
ans.add(cur);
for (DirectedGraphNode next : cur.neighbors) {
indegreeMap.put(next, indegreeMap.get(next) - 1);
if (indegreeMap.get(next) == 0) {
zeroQueue.offer(next);
}
}
}
return ans;
}
复制代码
2.2、方法二
public static class Record {
public DirectedGraphNode node;
public long nodes;
public Record(DirectedGraphNode n, long o) {
node = n;
nodes = o;
}
}
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
HashMap<DirectedGraphNode, Record> order = new HashMap<>();
for (DirectedGraphNode cur : graph) {
f(cur, order);
}
ArrayList<Record> recordArr = new ArrayList<>();
for (Record r : order.values()) {
recordArr.add(r);
}
recordArr.sort((o1, o2) -> Long.compare(o2.nodes, o1.nodes));
ArrayList<DirectedGraphNode> ans = new ArrayList<>();
for (Record r : recordArr) {
ans.add(r.node);
}
return ans;
}
// 当前来到cur点,请返回cur点所到之处,所有的点次!
// 返回(cur,点次)
// 缓存!!!!!order
// key : 某一个点的点次,之前算过了!
// value : 点次是多少
public static Record f(DirectedGraphNode cur, HashMap<DirectedGraphNode, Record> order) {
if (order.containsKey(cur)) {
return order.get(cur);
}
// cur的点次之前没算过!
long nodes = 0;
for (DirectedGraphNode next : cur.neighbors) {
nodes += f(next, order).nodes;
}
Record ans = new Record(cur, nodes + 1);
order.put(cur, ans);
return ans;
}
复制代码
四、总结
利用自定义图结构的入度(in),in为0代表指零个指向它的节点,按照这个原则实现图的拓扑排序
图的拓扑排序算法:
- 在图中找到所有入度为0的点输出
- 把所有入度为0的点在图中删掉,继续找入度为0的点输出,周而复始
- 图的所有点都被删除后,依次输出的顺序就是拓扑排序
要求:有向图且其中没有环
应用:事件安排、编译顺序