A ordem topológica deve ser um grafo acíclico direcionado.
A ordenação topológica não é única
Método de classificação topológica um:
Ordenar com grau zero
Ideia: Aquele que tiver grau de entrada 0 é o nó inicial.Após imprimir o nó inicial, reduza o grau de entrada dos vizinhos diretos do nó inicial em 1 e repita.
package algorithmbasic.class17;
import java.util.*;
//图的拓扑排序
public class TopologySort {
public static List<Node> sortedTopology(Graph graph) {
//result用来盛放排序结果。
List<Node> result = new ArrayList<>();
//inmap存放节点与入度的对应值。
//key ——> 某个节点, value ——> 剩余入度
HashMap<Node, Integer> inmap = new HashMap<>();
//只有节点的入度为0才可以进入此队列。
Queue<Node> inZeroQueue = new LinkedList<>();
for (Node node : graph.nodes.values()) {
inmap.put(node, node.in);
if (node.in == 0) {
inZeroQueue.add(node);
}
}
Node cur = inZeroQueue.poll();
result.add(cur);
for (Node next : cur.nexts) {
//剩余入度减1.
inmap.put(next, inmap.get(next) - 1);
if (inmap.get(next) == 0) {
inZeroQueue.add(next);
}
}
return result;
}
}
Método de classificação topológica dois:
Classificar por ponto.
Quanto maior o número de pontos, maior a posição de classificação.
E descobri que a recursão pode ser usada para encontrar pontos. Se pedirmos os pontos de 0, precisamos pedir os pontos de seus vizinhos diretos 1, 2 e 3, e então adicionar 1 à soma dos pontos dos vizinhos, que é o ponto de 0. Podemos colocar os pontos de cada ponto em uma tabela, e esta tabela registra quais pontos do nó correspondem a quantos. Dessa forma, quando solicitamos outros pontos de nó, podemos apenas retirá-los diretamente da mesa, reduzindo o trabalho repetitivo.
Idéias:
1: Criar uma tabela HashMap<DirectedGraphNode, Record> order = new HashMap<>() para registrar o número de pontos correspondentes a cada nó.2: Percorra cada nó em todo o grafo e registre seus tempos de ponto.
3: Crie uma tabela ordenada ArrayList records = new ArrayList<>() para registrar pontos.
4: Classificando de grande para pequeno de acordo com o número de pontos. registros sort(new MyComparator());
5: Em seguida, crie uma tabela ordenada ArrayList dnodes = new ArrayList<>() para registrar os nós de acordo com a ordem dos pontos.
Observe por que a classe interna Record foi criada. Porque ao "registrar os nós de acordo com a ordem dos pontos", precisamos encontrar os nós correspondentes de acordo com os pontos. Não é possível usar o mapa, porque o tamanho dos pontos é repetido. Portanto, usamos o método de classe interna, para que cada ponto tenha um nó correspondente um-para-um.
package algorithmbasic.class17;
//图的拓扑排序方法二
import java.util.*;
// OJ链接:https://www.lintcode.com/problem/topological-sorting
public class TopologicalOrderDFS2 {
/**
* 节点内部类
*/
// 不要提交这个类
public static class DirectedGraphNode {
public int label;
public ArrayList<DirectedGraphNode> neighbors;
public DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
}
/**
* 点次内部类。
*/
//记录某个节点的点次。
public static class Record {
public DirectedGraphNode node;
//点次。
public long nodes;
public Record(DirectedGraphNode node, long nodes) {
this.node = node;
this.nodes = nodes;
}
}
/**
* topSort方法
* 传入一张图的所有节点,返回排序好后的所有节点。
*/
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
//采用计算每个节点点次的方法。
//建立一张表用来记录每个节点对应的点次是多少。
HashMap<DirectedGraphNode, Record> order = new HashMap<>();
ArrayList<Record> records = new ArrayList<>();
ArrayList<DirectedGraphNode> dnodes = new ArrayList<>();
//遍历图中每个节点,并记录每个节点出现的点次。
for (DirectedGraphNode cur : graph) {
Record record = process(cur, order);
records.add(record);
//order.put(cur, record);
}
//Arrays.sort(records,new MyComparator());
records.sort(new MyComparator());
for (Record r : records) {
dnodes.add(r.node);//这就是为什么要建立Record这个内部类的原因。
}
return dnodes;
}
/**
* 求点次的方法。
*/
//传入一个节点返回这个节点的点次。在递归的过程当中每个节点的点次其实都已经记录好了。
public static Record process(DirectedGraphNode node, HashMap<DirectedGraphNode, Record> order) {
if (order.containsKey(node)) {
return order.get(node);
}
//order中没有该点。
long count = 0;
for (DirectedGraphNode n : node.neighbors) {
Record r = process(n, order);
count += r.nodes;
}
Record record = new Record(node, count + 1);
//先把当前节点及其点次放入map中然后再返回。这样我们再求其他节点点次时直接从表里拿就行,减少重复性工作。
order.put(node, record);
return record;
}
/**
* 比较器
*/
public static class MyComparator implements Comparator<Record> {
@Override
public int compare(Record o1, Record o2) {
//不要将long类型数据强制转换成int类型,会出现溢出和截断的风险,导致数据出现错误。
//例如2147483648L -> int:-2147483648
//它超过了int类型的最大值 2147483647。当将其强制转换为int类型时,结果被截断为int类型的最小值 -2147483648。
//return (int)(o2.nodes - o1.nodes);
return o1.nodes == o2.nodes ? 0 : (o1.nodes > o2.nodes ? -1 : 1);
}
}
}
Método de classificação topológica três:
classificar por profundidade
package algorithmbasic.class17;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
public class TopologicalOrderDFS1 {
/**
* 节点内部类
*/
public static class DirectedGraphNode {
public int label;
public ArrayList<DirectedGraphNode> neighbors;
public DirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<DirectedGraphNode>();
}
}
/**
* 深度内部类。
*/
public static class Deep {
public long deep;
public DirectedGraphNode node;
public Deep(long deep, DirectedGraphNode node) {
this.deep = deep;
this.node = node;
}
}
/**
* topSort方法
*/
public static ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
HashMap<DirectedGraphNode, Deep> order = new HashMap<>();
ArrayList<Deep> deeps = new ArrayList<>();
ArrayList<DirectedGraphNode> dNodes = new ArrayList<>();
for (DirectedGraphNode node : graph) {
Deep d = process(node, order);
deeps.add(d);
}
deeps.sort(new MyComparator());
for (Deep d : deeps) {
dNodes.add(d.node);
}
return dNodes;
}
public static Deep process(DirectedGraphNode node, HashMap<DirectedGraphNode, Deep> order) {
if (order.containsKey(node)) {
return order.get(node);
}
long max = Long.MIN_VALUE;
for (DirectedGraphNode n : node.neighbors) {
Deep d = process(n, order);
max = Math.max(max, d.deep);
}
Deep deep = new Deep(max + 1, node);
order.put(node, deep);
return deep;
}
public static class MyComparator implements Comparator<Deep> {
@Override
public int compare(Deep o1, Deep o2) {
return o1.deep == o2.deep ? 0 : (o1.deep > o2.deep ? -1 : 1);
}
}
}