题目
LintCode127
给定一个有向图,图节点的拓扑排序定义如下:
对于图中的每一条有向边 A -> B , 在拓扑排序中A一定在B之前.
拓扑排序中的第一个节点可以是图中的任何一个没有其他节点指向它的节点。
如下图所示:
拓扑排序可以为:
[0, 1, 2, 3, 4, 5]
[0, 2, 3, 1, 5, 4]
…
其中给定的数据结构是:表示的意思是DirectedGraphNode是一个点的描述类。label是点的value,neighbors是这个点所有的邻居。没有边的任何信息以及权重。
主方法就是topSort,根据给定的这个graph,实现它的拓扑排序。
class DirectedGraphNode {
int label;
List<DirectedGraphNode> neighbors;
DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
}
public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
}
分析
- 如果从A点出发经过所有的节点都算上为100。从B点出发经过所有的点都算上为80。那么就可以认为A的拓扑序在B的前面。两种情况。
1.1 AB点之间存在依赖关系,那么肯定是B依赖A点,不然不可能A所有的节点数>B所有节点数。
1.2 如果AB之间不存在依赖关系,那么AB谁在前无所谓,对于拓扑序来说,AB是在前都可以。所以可以规定如果A节点数>=B节点数。A的拓扑序在前。 - 如果节点数量特别多,如果想要得到0节点后面一共有多少节点数(以上图为例),那么它要遍历1,2,3,4,5后面所有的节点,想要得到1节点后面节点数也一样要遍历后面的所有。所以,为了更方便的获取到每个节点的后续所有节点数,用Map来作为缓存,算出来放到Map中。随用随取。
代码
//LintCode提供类,不要提交这个类
class DirectedGraphNode {
int label;
List<DirectedGraphNode> neighbors;
DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
}
public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
HashMap<DirectedGraphNode, Record> order = new HashMap<>();
//上来先计算出每个节点包含的子节点个数
for (DirectedGraphNode node : graph) {
f(node, order);
}
ArrayList<Record> records = new ArrayList<>();
for (Record record : order.values()) {
records.add(record);
}
//根据自己实现的比较器,进行排序(节点数量多的在前)
records.sort(new MyComparator());
//排序后,放到list,return
ArrayList<DirectedGraphNode> ans = new ArrayList<>();
for (Record record : records) {
ans.add(record.node);
}
return ans;
}
public static class Record {
public DirectedGraphNode node;
public long nodes;
public Record(long nodes, DirectedGraphNode node) {
this.nodes = nodes;
this.node = node;
}
}
//自定义比较器
public static class MyComparator implements Comparator<Record> {
@Override
public int compare(Record o1, Record o2) {
return o1.nodes == o2.nodes ? 0 : (o1.nodes > o2.nodes ? -1 : 1);
}
}
//f()函数用来计算每个节点后续包含多少节点
//cur:当前节点
//order:缓存Map,包含着每个节点后续挂了多少节点
public static Record f(DirectedGraphNode cur, HashMap<DirectedGraphNode, Record> order) {
//如果map中包含当前节点,说明已经算过了,直接return
if (order.containsKey(cur)) {
return order.get(cur);
}
long nodes = 0;
//拿到当前节点所有邻居
for (DirectedGraphNode next : cur.neighbors) {
//递归调用f()函数,累加
nodes += f(next, order).nodes;
}
//封装成Record,节点个数加上自己
Record record = new Record(nodes + 1, cur);
//放入map中随用随取
order.put(cur, record);
return record;
}