
有向图的边是有明确方向的








如果顶点 x 和 y 之间存在可相互抵达的路径(直接或间接的路径),则称 x 和 y 是连通的

如果有向图 G 中任意2个顶点都是连通的,则称G为强连通图


上面的图了解,过一遍就是可以的,去干饭干饭.
通过上面的图可以知道,它是关于对角线对称的.





上面的概念真是乱的很,下面开始写代码了.
抽象类:
- package com.mj.graph;
-
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
-
- public abstract class Graph
{ - protected WeightManager
weightManager; -
- public Graph() {}
-
- public Graph(WeightManager
weightManager) { - this.weightManager = weightManager;
- }
-
- public abstract int edgesSize();
- public abstract int verticesSize();
-
- public abstract void addVertex(V v);//顶点
- public abstract void addEdge(V from, V to);//边
- public abstract void addEdge(V from, V to, E weight);//权重
-
- public abstract void removeVertex(V v);
- public abstract void removeEdge(V from, V to);
-
- public abstract void bfs(V begin, VertexVisitor
visitor) ; - public abstract void dfs(V begin, VertexVisitor
visitor) ; -
- public abstract Set
> mst(); -
- public abstract List
topologicalSort(); -
- // public abstract Map
shortestPath(V begin); - public abstract Map
> shortestPath(V begin); -
- public abstract Map
>> shortestPath(); -
- public interface WeightManager
{ - int compare(E w1, E w2);
- E add(E w1, E w2);
- E zero();
- }
-
- public interface VertexVisitor
{ - boolean visit(V v);
- }
-
- public static class PathInfo
{ - protected E weight;
- protected List
> edgeInfos = new LinkedList<>(); - public PathInfo() {}
- public PathInfo(E weight) {
- this.weight = weight;
- }
- public E getWeight() {
- return weight;
- }
- public void setWeight(E weight) {
- this.weight = weight;
- }
- public List
> getEdgeInfos() { - return edgeInfos;
- }
- public void setEdgeInfos(List
> edgeInfos) { - this.edgeInfos = edgeInfos;
- }
- @Override
- public String toString() {
- return "PathInfo [weight=" + weight + ", edgeInfos=" + edgeInfos + "]";
- }
- }
-
- //定义的边
- public static class EdgeInfo
{ - private V from;//起始
- private V to;//终止
- private E weight;//权值
- public EdgeInfo(V from, V to, E weight) {
- this.from = from;
- this.to = to;
- this.weight = weight;
- }
- public V getFrom() {
- return from;
- }
- public void setFrom(V from) {
- this.from = from;
- }
- public V getTo() {
- return to;
- }
- public void setTo(V to) {
- this.to = to;
- }
- public E getWeight() {
- return weight;
- }
- public void setWeight(E weight) {
- this.weight = weight;
- }
- @Override
- public String toString() {
- return "EdgeInfo [from=" + from + ", to=" + to + ", weight=" + weight + "]";
- }
- }
- }
实现类:
- package com.mj.graph;
-
- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Objects;
- import java.util.Queue;
- import java.util.Set;
- import java.util.Stack;
-
- import com.mj.MinHeap;
- import com.mj.UnionFind;
-
- @SuppressWarnings("unchecked")
- public class ListGraph
extends Graph { - public ListGraph() {}
- public ListGraph(WeightManager
weightManager) { - super(weightManager);
- }
-
- private static class Vertex
{ - V value;
- Set
> inEdges = new HashSet<>(); - Set
> outEdges = new HashSet<>(); - Vertex(V value) {
- this.value = value;
- }
- @Override
- public boolean equals(Object obj) {
- return Objects.equals(value, ((Vertex
)obj).value); - }
- @Override
- public int hashCode() {
- return value == null ? 0 : value.hashCode();
- }
- @Override
- public String toString() {
- return value == null ? "null" : value.toString();
- }
- }
-
- private static class Edge
{ - Vertex
from; - Vertex
to; - E weight;
-
- Edge(Vertex
from, Vertex to) { - this.from = from;
- this.to = to;
- }
-
- EdgeInfo
info() { - return new EdgeInfo<>(from.value, to.value, weight);
- }
-
- @Override
- public boolean equals(Object obj) {
- Edge
edge = (Edge) obj; - return Objects.equals(from, edge.from) && Objects.equals(to, edge.to);
- }
- @Override
- public int hashCode() {
- return from.hashCode() * 31 + to.hashCode();
- }
-
- @Override
- public String toString() {
- return "Edge [from=" + from + ", to=" + to + ", weight=" + weight + "]";
- }
- }
-
- private Map
> vertices = new HashMap<>(); - private Set
> edges = new HashSet<>(); - private Comparator
> edgeComparator = (Edge e1, Edge e2) -> { - return weightManager.compare(e1.weight, e2.weight);
- };
-
- public void print() {
- System.out.println("[顶点]-------------------");
- vertices.forEach((V v, Vertex
vertex) -> { - System.out.println(v);
- System.out.println("out-----------");
- System.out.println(vertex.outEdges);
- System.out.println("in-----------");
- System.out.println(vertex.inEdges);
- });
-
- System.out.println("[边]-------------------");
- edges.forEach((Edge
edge) -> { - System.out.println(edge);
- });
- }
-
- @Override
- public int edgesSize() {
- return edges.size();
- }
-
- @Override
- public int verticesSize() {
- return vertices.size();
- }
-
- @Override
- public void addVertex(V v) {
- if (vertices.containsKey(v)) return;
- vertices.put(v, new Vertex<>(v));
- }
-
- @Override
- public void addEdge(V from, V to) {
- addEdge(from, to, null);
- }
-
- @Override
- public void addEdge(V from, V to, E weight) {
- Vertex
fromVertex = vertices.get(from); - if (fromVertex == null) {
- fromVertex = new Vertex<>(from);
- vertices.put(from, fromVertex);
- }
-
- Vertex
toVertex = vertices.get(to); - if (toVertex == null) {
- toVertex = new Vertex<>(to);
- vertices.put(to, toVertex);
- }
-
- Edge
edge = new Edge<>(fromVertex, toVertex); - edge.weight = weight;
- if (fromVertex.outEdges.remove(edge)) {
- toVertex.inEdges.remove(edge);
- edges.remove(edge);
- }
- fromVertex.outEdges.add(edge);
- toVertex.inEdges.add(edge);
- edges.add(edge);
- }
-
- @Override
- public void removeEdge(V from, V to) {
- Vertex
fromVertex = vertices.get(from); - if (fromVertex == null) return;
-
- Vertex
toVertex = vertices.get(to); - if (toVertex == null) return;
-
- Edge
edge = new Edge<>(fromVertex, toVertex); - if (fromVertex.outEdges.remove(edge)) {
- toVertex.inEdges.remove(edge);
- edges.remove(edge);
- }
- }
-
- @Override
- public void removeVertex(V v) {
- Vertex
vertex = vertices.remove(v); - if (vertex == null) return;
-
- for (Iterator
> iterator = vertex.outEdges.iterator(); iterator.hasNext();) { - Edge
edge = iterator.next(); - edge.to.inEdges.remove(edge);
- // 将当前遍历到的元素edge从集合vertex.outEdges中删掉
- iterator.remove();
- edges.remove(edge);
- }
-
- for (Iterator
> iterator = vertex.inEdges.iterator(); iterator.hasNext();) { - Edge
edge = iterator.next(); - edge.from.outEdges.remove(edge);
- // 将当前遍历到的元素edge从集合vertex.inEdges中删掉
- iterator.remove();
- edges.remove(edge);
- }
- }
-
- @Override
- public void bfs(V begin, VertexVisitor
visitor) { - if (visitor == null) return;
- Vertex
beginVertex = vertices.get(begin); - if (beginVertex == null) return;
-
- Set
> visitedVertices = new HashSet<>(); - Queue
> queue = new LinkedList<>(); - queue.offer(beginVertex);
- visitedVertices.add(beginVertex);
-
- while (!queue.isEmpty()) {
- Vertex
vertex = queue.poll(); - if (visitor.visit(vertex.value)) return;
-
- for (Edge
edge : vertex.outEdges) { - if (visitedVertices.contains(edge.to)) continue;
- queue.offer(edge.to);
- visitedVertices.add(edge.to);
- }
- }
- }
-
- @Override
- public void dfs(V begin, VertexVisitor
visitor) { - if (visitor == null) return;
- Vertex
beginVertex = vertices.get(begin); - if (beginVertex == null) return;
-
- Set
> visitedVertices = new HashSet<>(); - Stack
> stack = new Stack<>(); -
- // 先访问起点
- stack.push(beginVertex);
- visitedVertices.add(beginVertex);
- if (visitor.visit(begin)) return;
-
- while (!stack.isEmpty()) {
- Vertex
vertex = stack.pop(); -
- for (Edge
edge : vertex.outEdges) { - if (visitedVertices.contains(edge.to)) continue;
-
- stack.push(edge.from);
- stack.push(edge.to);
- visitedVertices.add(edge.to);
- if (visitor.visit(edge.to.value)) return;
-
- break;
- }
- }
- }
-
- @Override
- public List
topologicalSort() { - List
list = new ArrayList<>(); - Queue
> queue = new LinkedList<>(); - Map
, Integer> ins = new HashMap<>(); - // 初始化(将度为0的节点都放入队列)
- vertices.forEach((V v, Vertex
vertex) -> { - int in = vertex.inEdges.size();
- if (in == 0) {
- queue.offer(vertex);
- } else {
- ins.put(vertex, in);
- }
- });
-
- while (!queue.isEmpty()) {
- Vertex
vertex = queue.poll(); - // 放入返回结果中
- list.add(vertex.value);
-
- for (Edge
edge : vertex.outEdges) { - int toIn = ins.get(edge.to) - 1;
- if (toIn == 0) {
- queue.offer(edge.to);
- } else {
- ins.put(edge.to, toIn);
- }
- }
- }
-
- return list;
- }
-
- @Override
- public Set
> mst() { - return Math.random() > 0.5 ? prim() : kruskal();
- }
-
- private Set
> prim() { - Iterator
> it = vertices.values().iterator(); - if (!it.hasNext()) return null;
- Vertex
vertex = it.next(); - Set
> edgeInfos = new HashSet<>(); - Set
> addedVertices = new HashSet<>(); - addedVertices.add(vertex);
- MinHeap
> heap = new MinHeap<>(vertex.outEdges, edgeComparator); - int verticesSize = vertices.size();
- while (!heap.isEmpty() && addedVertices.size() < verticesSize) {
- Edge
edge = heap.remove(); - if (addedVertices.contains(edge.to)) continue;
- edgeInfos.add(edge.info());
- addedVertices.add(edge.to);
- heap.addAll(edge.to.outEdges);
- }
- return edgeInfos;
- }
-
- private Set
> kruskal() { - int edgeSize = vertices.size() - 1;
- if (edgeSize == -1) return null;
- Set
> edgeInfos = new HashSet<>(); - MinHeap
> heap = new MinHeap<>(edges, edgeComparator); - UnionFind
> uf = new UnionFind<>(); - vertices.forEach((V v, Vertex
vertex) -> { - uf.makeSet(vertex);
- });
- while (!heap.isEmpty() && edgeInfos.size() < edgeSize) {
- Edge
edge = heap.remove(); - if (uf.isSame(edge.from, edge.to)) continue;
- edgeInfos.add(edge.info());
- uf.union(edge.from, edge.to);
- }
- return edgeInfos;
- }
-
- // public Map
shortestPath(V begin) { - // Vertex
beginVertex = vertices.get(begin); - // if (beginVertex == null) return null;
- //
- // Map
selectedPaths = new HashMap<>(); - // Map
, E> paths = new HashMap<>(); - // // 初始化paths
- // for (Edge
edge : beginVertex.outEdges) { - // paths.put(edge.to, edge.weight);
- // }
- //
- // while (!paths.isEmpty()) {
- // Entry
, E> minEntry = getMinPath(paths); - // // minVertex离开桌面
- // Vertex
minVertex = minEntry.getKey(); - // selectedPaths.put(minVertex.value, minEntry.getValue());
- // paths.remove(minVertex);
- // // 对它的minVertex的outEdges进行松弛操作
- // for (Edge
edge : minVertex.outEdges) { - // // 如果edge.to已经离开桌面,就没必要进行松弛操作
- // if (selectedPaths.containsKey(edge.to.value)) continue;
- // // 新的可选择的最短路径:beginVertex到edge.from的最短路径 + edge.weight
- // E newWeight = weightManager.add(minEntry.getValue(), edge.weight);
- // // 以前的最短路径:beginVertex到edge.to的最短路径
- // E oldWeight = paths.get(edge.to);
- // if (oldWeight == null || weightManager.compare(newWeight, oldWeight) < 0) {
- // paths.put(edge.to, newWeight);
- // }
- // }
- // }
- //
- // selectedPaths.remove(begin);
- // return selectedPaths;
- // }
-
- @Override
- public Map
> shortestPath(V begin) { - return dijkstra(begin);
- }
-
- @SuppressWarnings("unused")
- private Map
> bellmanFord(V begin) { - Vertex
beginVertex = vertices.get(begin); - if (beginVertex == null) return null;
-
- Map
> selectedPaths = new HashMap<>(); - selectedPaths.put(begin, new PathInfo<>(weightManager.zero()));
-
- int count = vertices.size() - 1;
- for (int i = 0; i < count; i++) { // v - 1 次
- for (Edge
edge : edges) { - PathInfo
fromPath = selectedPaths.get(edge.from.value); - if (fromPath == null) continue;
- relax(edge, fromPath, selectedPaths);
- }
- }
-
- for (Edge
edge : edges) { - PathInfo
fromPath = selectedPaths.get(edge.from.value); - if (fromPath == null) continue;
- if (relax(edge, fromPath, selectedPaths)) {
- System.out.println("有负权环");
- return null;
- }
- }
-
- selectedPaths.remove(begin);
- return selectedPaths;
- }
-
-
- /**
- * 松弛
- * @param edge 需要进行松弛的边
- * @param fromPath edge的from的最短路径信息
- * @param paths 存放着其他点(对于dijkstra来说,就是还没有离开桌面的点)的最短路径信息
- */
- private boolean relax(Edge
edge, PathInfo fromPath, Map> paths) { - // 新的可选择的最短路径:beginVertex到edge.from的最短路径 + edge.weight
- E newWeight = weightManager.add(fromPath.weight, edge.weight);
- // 以前的最短路径:beginVertex到edge.to的最短路径
- PathInfo
oldPath = paths.get(edge.to.value); - if (oldPath != null && weightManager.compare(newWeight, oldPath.weight) >= 0) return false;
-
- if (oldPath == null) {
- oldPath = new PathInfo<>();
- paths.put(edge.to.value, oldPath);
- } else {
- oldPath.edgeInfos.clear();
- }
-
- oldPath.weight = newWeight;
- oldPath.edgeInfos.addAll(fromPath.edgeInfos);
- oldPath.edgeInfos.add(edge.info());
-
- return true;
- }
-
- private Map
> dijkstra(V begin) { - Vertex
beginVertex = vertices.get(begin); - if (beginVertex == null) return null;
-
- Map
> selectedPaths = new HashMap<>(); - Map
, PathInfo> paths = new HashMap<>(); - paths.put(beginVertex, new PathInfo<>(weightManager.zero()));
- // 初始化paths
- // for (Edge
edge : beginVertex.outEdges) { - // PathInfo
path = new PathInfo<>(); - // path.weight = edge.weight;
- // path.edgeInfos.add(edge.info());
- // paths.put(edge.to, path);
- // }
-
- while (!paths.isEmpty()) {
- Entry
, PathInfo> minEntry = getMinPath(paths); - // minVertex离开桌面
- Vertex
minVertex = minEntry.getKey(); - PathInfo
minPath = minEntry.getValue(); - selectedPaths.put(minVertex.value, minPath);
- paths.remove(minVertex);
- // 对它的minVertex的outEdges进行松弛操作
- for (Edge
edge : minVertex.outEdges) { - // 如果edge.to已经离开桌面,就没必要进行松弛操作
- if (selectedPaths.containsKey(edge.to.value)) continue;
- relaxForDijkstra(edge, minPath, paths);
- }
- }
-
- selectedPaths.remove(begin);
- return selectedPaths;
- }
-
- /**
- * 松弛
- * @param edge 需要进行松弛的边
- * @param fromPath edge的from的最短路径信息
- * @param paths 存放着其他点(对于dijkstra来说,就是还没有离开桌面的点)的最短路径信息
- */
- private void relaxForDijkstra(Edge
edge, PathInfo fromPath, Map, PathInfo> paths) { - // 新的可选择的最短路径:beginVertex到edge.from的最短路径 + edge.weight
- E newWeight = weightManager.add(fromPath.weight, edge.weight);
- // 以前的最短路径:beginVertex到edge.to的最短路径
- PathInfo
oldPath = paths.get(edge.to); - if (oldPath != null && weightManager.compare(newWeight, oldPath.weight) >= 0) return;
-
- if (oldPath == null) {
- oldPath = new PathInfo<>();
- paths.put(edge.to, oldPath);
- } else {
- oldPath.edgeInfos.clear();
- }
-
- oldPath.weight = newWeight;
- oldPath.edgeInfos.addAll(fromPath.edgeInfos);
- oldPath.edgeInfos.add(edge.info());
- }
-
- /**
- * 从paths中挑一个最小的路径出来
- * @param paths
- * @return
- */
- private Entry
, PathInfo> getMinPath(Map, PathInfo> paths) { - Iterator
, PathInfo>> it = paths.entrySet().iterator(); - Entry
, PathInfo> minEntry = it.next(); - while (it.hasNext()) {
- Entry
, PathInfo> entry = it.next(); - if (weightManager.compare(entry.getValue().weight, minEntry.getValue().weight) < 0) {
- minEntry = entry;
- }
- }
- return minEntry;
- }
-
- @Override
- public Map
>> shortestPath() { - Map
>> paths = new HashMap<>(); - // 初始化
- for (Edge
edge : edges) { - Map
> map = paths.get(edge.from.value); - if (map == null) {
- map = new HashMap<>();
- paths.put(edge.from.value, map);
- }
-
- PathInfo
pathInfo = new PathInfo<>(edge.weight); - pathInfo.edgeInfos.add(edge.info());
- map.put(edge.to.value, pathInfo);
- }
-
- vertices.forEach((V v2, Vertex
vertex2) -> { - vertices.forEach((V v1, Vertex
vertex1) -> { - vertices.forEach((V v3, Vertex
vertex3) -> { - if (v1.equals(v2) || v2.equals(v3) || v1.equals(v3)) return;
-
- // v1 -> v2
- PathInfo
path12 = getPathInfo(v1, v2, paths); - if (path12 == null) return;
-
- // v2 -> v3
- PathInfo
path23 = getPathInfo(v2, v3, paths); - if (path23 == null) return;
-
- // v1 -> v3
- PathInfo
path13 = getPathInfo(v1, v3, paths); -
- E newWeight = weightManager.add(path12.weight, path23.weight);
- if (path13 != null && weightManager.compare(newWeight, path13.weight) >= 0) return;
-
- if (path13 == null) {
- path13 = new PathInfo
(); - paths.get(v1).put(v3, path13);
- } else {
- path13.edgeInfos.clear();
- }
-
- path13.weight = newWeight;
- path13.edgeInfos.addAll(path12.edgeInfos);
- path13.edgeInfos.addAll(path23.edgeInfos);
- });
- });
- });
-
- return paths;
- }
-
- private PathInfo
getPathInfo(V from, V to, Map>> paths) { - Map
> map = paths.get(from); - return map == null ? null : map.get(to);
- }
-
- // @Override
- // public void bfs(V begin) {
- // Vertex
beginVertex = vertices.get(begin); - // if (beginVertex == null) return;
- //
- // Set
> visitedVertices = new HashSet<>(); - // Queue
> queue = new LinkedList<>(); - // queue.offer(beginVertex);
- // visitedVertices.add(beginVertex);
- //
- // while (!queue.isEmpty()) {
- // Vertex
vertex = queue.poll(); - // System.out.println(vertex.value);
- //
- // for (Edge
edge : vertex.outEdges) { - // if (visitedVertices.contains(edge.to)) continue;
- // queue.offer(edge.to);
- // visitedVertices.add(edge.to);
- // }
- // }
- // }
- //
- // @Override
- // public void dfs(V begin) {
- // Vertex
beginVertex = vertices.get(begin); - // if (beginVertex == null) return;
- //
- // Set
> visitedVertices = new HashSet<>(); - // Stack
> stack = new Stack<>(); - //
- // // 先访问起点
- // stack.push(beginVertex);
- // visitedVertices.add(beginVertex);
- // System.out.println(beginVertex.value);
- //
- // while (!stack.isEmpty()) {
- // Vertex
vertex = stack.pop(); - //
- // for (Edge
edge : vertex.outEdges) { - // if (visitedVertices.contains(edge.to)) continue;
- //
- // stack.push(edge.from);
- // stack.push(edge.to);
- // visitedVertices.add(edge.to);
- // System.out.println(edge.to.value);
- //
- // break;
- // }
- // }
- // }
-
- // public void dfs2(V begin) {
- // Vertex
beginVertex = vertices.get(begin); - // if (beginVertex == null) return;
- // dfs2(beginVertex, new HashSet<>());
- // }
- //
- // private void dfs2(Vertex
vertex, Set> visitedVertices) { - // System.out.println(vertex.value);
- // visitedVertices.add(vertex);
- //
- // for (Edge
edge : vertex.outEdges) { - // if (visitedVertices.contains(edge.to)) continue;
- // dfs2(edge.to, visitedVertices);
- // }
- // }
- }