拓扑排序 topologicalSort
背景知识 ---- 图 (Graph)
顶点和边 (vertex and edge)
下图中的数字为图的顶点,数字之间的线为图的边
无向图 (Undirected Graph)
下图中顶点和顶点之间是没有方向性的,可以双向通行。
也就是同时存在 (1, 2) 和 (2, 1)
有向图 (Directed Graph)
下图是有方向性的,只能往箭头的方向通行
也就是只存在 (1, 2), 不存在 (2, 1)
有向图的degree
- 对于有向图,每个顶点都有一个degree,并且分为
- in-degree: number of edgs into vertex a
- out-degree: number of edges out of vertex a
- 下图中
1: in-degree = 0, out-degree = 1
2: in-degree = 2, out-degree = 1
3: in-degree = 0, out-degree = 2
4: in-degree = 2, out-degree = 0
图中的环
图中可以形成回路的是环
下图中 2 —> 4 ----> 3 —> 2,就形成了环
基本概念
什么是拓扑排序
- 对于一个有向无环图,将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前
- 如下图: 2 永远不可能在 1和3之前出现,4 用于不可能在1,2,3之前出现
- 拓扑排序不是传统的排序算法,一个图可能有多种拓扑排序
下图的拓扑排序是: 1,3,2,4 或者 3,1,2,4,有两种拓扑排序
拓扑排序的代码思路 — 利用广度优先搜索(BFS)
- 统计每个点的 in-degree
- 将每个in-degree为0的点放进队列 (Queue),作为初始值
- 不断的从队列里拿出一个点 (pop操作), 将这个点的所有邻居的indegree减1
- 如果发现有新的indegree为0的点,则放入队列
- 重复3,4步,直到队列为空
Example:
Step 1: 初始化队列:
Queue: {1,3} 因为1和3的indegree为0
Output: { };
Step 2:队首元素出队放入output, 更新2的indegree为 1
Queue: {3}
Output: {1};
Step 3: 队首元素出队放入output, 更新2的indegree为 0, 同时将 2 放进 Queue
Queue: {2}
Output: {1, 3};
Step 4: 队首元素出队放入output, 更新4的indegree为 0, 同时将 4 放进 Queue
Queue: {4}
Output: {1, 3, 2};
Step 3: 队首元素出队放入output, Queue为空,结束顺换,排序完成
Queue: {}
Output: {1, 3, 2, 4};
拓扑排序的实现
/**
* Definition for Directed graph.
* class DirectedGraphNode {
* int label;
* ArrayList<DirectedGraphNode> neighbors;
* DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
* };
*/
public class Solution {
/*
* @param graph: A list of Directed graph node
* @return: Any topological order for the given graph.
*/
public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
ArrayList<DirectedGraphNode> outputList = new ArrayList<DirectedGraphNode>();
//用于储存每个点的inderee
HashMap