拓扑排序
- 拓扑排序-lintcode原题
- 题目介绍
- 解题思路
- 代码演示
- 解题方法二 (参考,不用掌握)
- 前置知识 图的拓扑序和深度优先遍历和广度优先遍历
拓扑排序-lintcode原题
127.拓扑排序-原题链接,可以点进去测试
题目介绍
描述
给定一个有向图,图节点的拓扑排序定义如下:
对于图中的每一条有向边 A -> B , 在拓扑排序中A一定在B之前.
拓扑排序中的第一个节点可以是图中的任何一个没有其他节点指向它的节点.
针对给定的有向图找到任意一种拓扑排序的顺序.
样例:
输入:
graph = {0,1,2,3#1,4#2,4,5#3,4,5#4#5}
输出:
[0, 1, 2, 3, 4, 5]
解释:
拓扑排序可以为:
[0, 1, 2, 3, 4, 5]
[0, 2, 3, 1, 5, 4]
…
您只需要返回给定图的任何一种拓扑顺序。
解题思路
我们用图的深度优先遍历去解决这个题.
由于拓扑序不唯一,但我们可以定一个标准,深度越深的节点,拓扑序越靠前.
我们用深度优先遍历,把图节点的深度都拿到,保存在一个表中,
我们再根据深度去排序,就得到递归序了,我们上代码演示.
代码演示
1.lintcode 提供的图结构
public static class DirectedGraphNode {
public int label;
public ArrayList<DirectedGraphNode> neighbors;
public DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
}
- 下面代码可以直接复制进去测试
/**
* 拓扑序
* @param graph
* @return
*/
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
HashMap<DirectedGraphNode, Record> order = new HashMap<>();
//拿到每个点的深度
for (DirectedGraphNode node : graph){
process(node,order);
}
//排序好的节点放进集合中 方便排序
ArrayList<Record> records = new ArrayList<>();
for (Record record : order.values()){
records.add(record);
}
//使用自定义比较器去排序
records.sort(new MyComparator());
ArrayList<DirectedGraphNode> ans = new ArrayList<>();
for (Record re : records){
ans.add(re.node);
}
return ans;
}
/**
* 记录每个几点的最大深度
*/
public static class Record{
//节点
DirectedGraphNode node;
//深度
int deep;
public Record(DirectedGraphNode node, int deep) {
this.node = node;
this.deep = deep;
}
}
/**
* 自定义比较器,深度越深的,就排在前面.
*/
public static class MyComparator implements Comparator<Record>{
@Override
public int compare(Record o1, Record o2) {
return o2.deep - o1.deep;
}
}
/**
* 递归去记录每个节点的最大深度
* @param node
* @return
*/
public static Record process(DirectedGraphNode node, HashMap<DirectedGraphNode,Record>orders){
//记忆化搜索,记录每次的结果,如果已经有了就直接拿结果返回.
if (orders.containsKey(node)){
return orders.get(node);
}
int deep = 0;
//拿到节点最大深度
for (DirectedGraphNode cur : node.neighbors){
deep = Math.max(deep,process(cur,orders).deep);
}
Record record = new Record(node, deep + 1);
orders.put(node,record);
return record;
}
解题方法二 (参考,不用掌握)
思路:
和方法一类似,在递归的过程中,我们不计算最大深度了,我们拿到每个点下面出现了多少次别的点.
出现点次越多的,我们认为拓扑序越靠前.
举例:
如果a点后面还有五个点,b 后面有四个点,我们认为a 的拓扑序更靠前/
直接代码展示,可以提交测试.
/**
* 排序.
* @param graph
* @return
*/
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph){
HashMap<DirectedGraphNode, Record> map = new HashMap<>();
for (DirectedGraphNode node : graph){
process(node, map);
}
ArrayList<Record> records = new ArrayList<>();
for (Record re : map.values()){
records.add(re);
}
records.sort(new MyComparator());
ArrayList<DirectedGraphNode> directedGraphNodes = new ArrayList<>();
for (Record record : records){
directedGraphNodes.add(record.node);
}
return directedGraphNodes;
}
/**
* 记录每个点在深度遍历时 后面点出现的点次的概念
*/
public static class Record{
public DirectedGraphNode node;
public long nodes;
public Record(DirectedGraphNode node, long nodes) {
this.node = node;
this.nodes = nodes;
}
}
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);
}
}
/**
* 递归算法 计算每个点出现的点次
* @param node
* @param records
* @return
*/
public static Record process(DirectedGraphNode node, HashMap<DirectedGraphNode,Record> records){
if (records.containsKey(node)){
return records.get(node);
}
long nodes = 0;
for (DirectedGraphNode cur : node.neighbors){
nodes += process(cur,records).nodes;
}
Record record = new Record(node, nodes + 1);
records.put(node,record);
return record;
}
前置知识 图的拓扑序和深度优先遍历和广度优先遍历
图的拓扑排序(java)
图的深度优先遍历和广度优先遍历(java)
图结构-图的数据表示法(java)