1. 图的实现
Graph.java
public class Graph {
public HashMap<Integer, Node> nodes;
public HashSet<Edge> edges;
public Graph() {
this.nodes = new HashMap<>();
this.edges = new HashSet<>();
}
}
Edge.java
public class Edge {
public int weight;
public Node from;
public Node to;
public Edge(int weight, Node from, Node to) {
this.weight = weight;
this.from = from;
this.to = to;
}
}
Node.java
```java
public class Node {
public int value;
public int in;
public int out;
public ArrayList<Node> nexts;
public ArrayList<Edge> edges;
public Node(int value) {
this.value = value;
this.in = 0;
this.out = 0;
this.nexts = new ArrayList<>();
this.edges = new ArrayList<>();
}
}
- 创建了Graph类以及Graph中的Edge类和Node类后,可能会遇到许多表示图的方式,但是包含的信息全部都在Graph类中。不管表达方式怎么变,将这些方式中的信息填入到创建的Graph类中,就可在后续写图算法时更加方便。
- 以其中一种图表达方式为例进行转换:N*3的矩阵,每一个数组表示[from节点的符号值,to节点的符号值,连接两个点的边的权重]
public static Graph createGraph(Integer[][] matrix) {
Graph graph = new Graph();
for (int i = 0; i < matrix.length; i++) {
Integer from = matrix[i][0];
Integer to = matrix[i][1];
Integer weight = matrix[i][2];
if (!graph.nodes.containsKey(from)) {
graph.nodes.put(from, new Node(from));
}
if (!graph.nodes.containsKey(to)) {
graph.nodes.put(to, new Node(to));
}
Node fromNode = graph.nodes.get(from);
Node toNode = graph.nodes.get(to);
Edge newEdge = new Edge(weight, fromNode, toNode);
fromNode.nexts.add(toNode);
fromNode.out++;
toNode.in++;
fromNode.edges.add(newEdge);
graph.edges.add(newEdge);
}
return graph;
}
2. 图的宽度优先遍历
public class BFS {
public static void bfs(Node node){
if (node == null){
return;
}
Queue<Node> queue = new LinkedList<>();
HashSet<Node> map = new HashSet<>();
queue.add(node);
map.add(node);
while (!queue.isEmpty()){
Node cur = queue.poll();
System.out.println(cur.value);
for (Node next : cur.nexts){
if (!map.contains(next)){
map.add(next);
queue.add(next);
}
}
}
}
}
3. 图的深度优先遍历
public class DFS {
public static void dfs(Node node) {
if (node == null) {
return;
}
Stack<Node> stack = new Stack<>();
HashSet<Node> map = new HashSet<>();
stack.add(node);
map.add(node);
System.out.println(node);
while (!stack.isEmpty()) {
Node cur = stack.pop();
for (Node next : cur.nexts) {
if (!map.contains(next)) {
stack.push(cur);
stack.push(next);
map.add(next);
System.out.println(next.value);
break;
}
}
}
}
}
4. 拓扑排序
拓扑排序:以项目中的依赖包为例,假设B包依赖A包,C包依赖A包和B包,D包依赖B包和C包,如何确定包的编译顺序?
下图为一个有向无环图
A --> B --> C --> D
| | ↑ ↑
------|------ |
-------------
1. 找到入度为0的点,图中为A
2. 将A点和A相关的边全部移除,A就称为第一个编译的包
3. 再次重复1-2直到所有节点排好序
public class TopologySort {
public static List<Node> sortedTopology(Graph graph){
HashMap<Node, Integer> inMap = new HashMap<>();
Queue<Node> zeroInqueue = new LinkedList<>();
for (Node node : graph.nodes.values()){
inMap.put(node, node.in);
if (node.in == 0){
zeroInqueue.add(node);
}
}
List<Node> result = new ArrayList<>();
while (!zeroInqueue.isEmpty()){
Node cur = zeroInqueue.poll();
result.add(cur);
for (Node next : cur.nexts){
inMap.put(next, inMap.get(next)-1);
if (inMap.get(next) == 0){
zeroInqueue.add(next);
}
}
}
return result;
}
}
|