引言
本文整理了常见的图排序相关算法,方便以后查阅。更多相关文章和其他文章均收录于贝贝猫的文章目录。
图
BFS
package bbm.graph;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import static bbm.graph.BFS.Color.BLACK;
import static bbm.graph.BFS.Color.GRAY;
import static bbm.graph.BFS.Color.WHITE;
/**
* 图的广度优先搜索,以链表的形式表述邻接关系, 这里我们利用队列来实现 BFS
*
* BFS 可以用来计算最短路径
*
* @author bbm
*/
public class BFS {
public static class Node {
String name;
Color color = WHITE;
int d = Integer.MAX_VALUE;
Node pre = null;
List<Node> neighbors = new LinkedList<>();
public Node(String name) {
this.name = name;
}
}
public static enum Color {
WHITE,
GRAY,
BLACK
}
public static void bfs(Node node) {
LinkedBlockingQueue<Node> queue = new LinkedBlockingQueue<>();
node.color = GRAY;
node.d = 0;
node.pre = null;
queue.offer(node);
while (!queue.isEmpty()) {
Node current = queue.poll();
current.neighbors.forEach(neighbor -> {
if (neighbor.color.equals(WHITE)) {
neighbor.color = GRAY;
neighbor.d = current.d + 1;
neighbor.pre = current;
queue.offer(neighbor);
}
});
current.color = BLACK;
System.out.println("Node " + current.name + ", d: " + current.d);
}
}
public static void main(String[] args) {
Node s = new Node("s");
Node r = new Node("r");
Node v = new Node("v");
Node w = new Node("w");
Node t = new Node("t");
Node x = new Node("x");
Node y = new Node("y");
Node u = new Node("u");
s.neighbors.add(w);
s.neighbors.add(r);
r.neighbors.add(s);
r.neighbors.add(v);
v.neighbors.add(r);
w.neighbors.add(s);
w.neighbors.add(t);
w.neighbors.add(x);
t.neighbors.add(u);
t.neighbors.add(x);
t.neighbors.add(w);
x.neighbors.add(w);
x.neighbors.add(t);
x.neighbors.add(y);
x.neighbors.add(u);
y.neighbors.add(x);
y.neighbors.add(u);
u.neighbors.add(t);
u.neighbors.add(x);
u.neighbors.add(y);
bfs(s);
System.out.println("Path from s to y:");
printPath(s, y);
System.out.println();
}
private static void printPath(Node s, Node y) {
if (s == y) {
System.out.print(s.name + " ");
} else {
if (y.pre == null) {
System.out.println("No path from " + s.name + " to " + y.name);
} else {
printPath(s, y.pre);
System.out.print(y.name + " ");
}
}
}
}
DFS
package bbm.graph;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import static bbm.graph.DFS.Color.BLACK;
import static bbm.graph.DFS.Color.GRAY;
import static bbm.graph.DFS.Color.WHITE;
/**
* 图的广度优先搜索,用颜色来表示是否已经开始处理某一个节点,白色:未处理,灰色:处理中,黑色:处理完
*
* 如果我们将每个节点的开始处理时间记为 startTime 处理完成时间记录为 endTime 那么我们可以通过 startTime 和 endTime 够成一个括号化结构
* Node x, start:4 end:5 被包含在 Node y, start:3 end:6 之中,这实际上就是一个树形结构, 当 x 节点的 start 和 end 在 y 节点的
* start end 范围内时,x 节点就是 y 节点的子节点
* y(3, 6)
* /
* x(4,5)
*
* 通过这个深度优先树,我们可以简单的通过检查是否有由子节点到父节点的边来判断图中是否有环
* @author bbm
*/
public class DFS {
public static class Node {
String name;
Color color = WHITE;
int startTime;
int endTime;
Node pre = null;
List<Node> neighbors = new LinkedList<>();
public Node(String name) {
this.name = name;
}
}
public static enum Color {
WHITE,
GRAY,
BLACK
}
public static int time = 0;
public static void dfs(List<Node> graph) {
graph.forEach(node -> {
if (node.color.equals(WHITE)) {
visit(node);
}
});
}
private static void visit(Node node) {
time += 1;
node.startTime = time;
node.color = GRAY;
node.neighbors.forEach(neighbor -> {
if (neighbor.color.equals(WHITE)) {
neighbor.pre = node;
visit(neighbor);
}
});
node.color = BLACK;
time += 1;
node.endTime = time;
System.out.println("Node " + node.name + ", start:" + node.startTime + " end:" + node.endTime);
}
public static void main(String[] args) {
Node u = new Node("u");
Node v = new Node("v");
Node w = new Node("w");
Node x = new Node("x");
Node y = new Node("y");
Node z = new Node("z");
u.neighbors.add(v);
u.neighbors.add(x);
v.neighbors.add(y);
w.neighbors.add(y);
w.neighbors.add(z);
x.neighbors.add(v);
y.neighbors.add(x);
z.neighbors.add(z);
List<Node> graph = Arrays.asList(u, v, w, x, y, z);
dfs(graph);
}
}
拓扑排序
package bbm.graph;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import static bbm.graph.TopologicalOrder.Color.GRAY;
import static bbm.graph.TopologicalOrder.Color.WHITE;
/**
* 当且仅当图中没有定向环时(即有向无环图),才有可能进行拓扑排序。
*
* 在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,才能称为该图的一个拓扑排序(英语:Topological sorting):
* 1. 序列中包含每个顶点,且每个顶点只出现一次;
* 2. 若A在序列中排在B的前面,则在图中不存在从B到A的路径。
*
*
* @author bbm
*/
public class TopologicalOrder {
public static class Node {
String name;
Color color = WHITE;
int startTime;
int endTime;
Node pre = null;
List<Node> next = new LinkedList<>();
public Node(String name) {
this.name = name;
}
}
public static enum Color {
WHITE,
GRAY,
BLACK
}
public static int time = 0;
public static void dfs(List<Node> graph) {
graph.forEach(node -> {
if (node.color.equals(WHITE)) {
visit(node);
}
});
}
private static void visit(Node node) {
time += 1;
node.startTime = time;
node.color = GRAY;
node.next.forEach(neighbor -> {
if (neighbor.color.equals(WHITE)) {
neighbor.pre = node;
visit(neighbor);
}
});
node.color = Color.BLACK;
time += 1;
node.endTime = time;
}
public static void topologicalSort(List<Node> nodes) {
dfs(nodes);
nodes.sort((o1, o2) -> o2.endTime - o1.endTime);
for (Node node : nodes) {
System.out.print(node.name + " ");
}
}
public static void main(String[] args) {
Node w = new Node("袜子");
Node n = new Node("内裤");
Node k = new Node("裤子");
Node x = new Node("鞋子");
Node s = new Node("手表");
Node c = new Node("衬衣");
Node y = new Node("腰带");
Node l = new Node("领带");
Node j = new Node("夹克");
w.next.add(x);
n.next.addAll(Arrays.asList(k, x));
k.next.addAll(Arrays.asList(x, y));
c.next.addAll(Arrays.asList(y, l));
y.next.add(j);
l.next.add(j);
List<Node> nodes = Arrays.asList(w, n, k, x, s, c, y, l, j);
topologicalSort(nodes);
}
}
参考内容
[1] 《算法导论》