1、制定图的模板结构:
package learn;
import java.util.HashMap;
import java.util.HashSet;
public class Graph {
public HashMap<Integer,Node> nodes;//点的编号,实际点 点集
public HashSet<Edge> edges;//边集
public Graph(){//构造函数
nodes=new HashMap<Integer, Node>();
edges=new HashSet<Edge>();
}
}
package learn;
import java.util.ArrayList;
public class Node {
public int value;
public int in;//有多少入度
public int out;//出度
public ArrayList<Node> nexts;//Node指向的邻接点
public ArrayList<Edge> edges;//属于Node的边
public Node(int value){
this.value=value;
in=0;
out=0;
nexts=new ArrayList<>();
edges=new ArrayList<>();
}
}
package learn;
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;
}
}
2、将题目给定的图结构转化为模板结构
例子:
package learn;
public class Demo {
public static Graph creatGraph(Integer[][] matrix) {//将二维数组存储的图结构转化为模板图结构
Graph g=new Graph();
for(int i=0;i<matrix.length;i++) {//matrix.length 获取行数
Integer weight = matrix[i][0];
Integer from=matrix[i][1];
Integer to=matrix[i][2];
//如果graph的nodes中没有form to两点,将其加入点集
if(!g.nodes.containsKey(from)){
g.nodes.put(from,new Node(from));
}
if(!g.nodes.containsKey(to)){
g.nodes.put(from,new Node(to));
}
Node fromNode=g.nodes.get(from);
Node toNode=g.nodes.get(to);
Edge e=new Edge(weight,fromNode,toNode);
g.edges.add(e);//加入图的边集
fromNode.out++;
toNode.in++;
fromNode.nexts.add(toNode);
fromNode.edges.add(e);
}
return g;
}
}
3、BFS: 队列和set
package learn;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class BFS_Code {
public static void bfs(Node node) {
if(node==null)return;
Queue<Node> q=new LinkedList<>();
HashSet<Node> s=new HashSet<>();
q.add(node);
s.add(node);
while (!q.isEmpty()){
Node n=q.poll();
System.out.println(n.value);
for(Node next:n.nexts){
if(!s.contains(next)){
q.add(next);
s.add(next);
}
}
}
}
}
4、DFS:栈和set
package learn;
import java.util.HashSet;
import java.util.Stack;
public class DFS {
public static void dfs(Node node) {
if(node==null)return;
Stack<Node> s=new Stack<>();
HashSet<Node> hs=new HashSet<>();
s.add(node);
hs.add(node);
System.out.println(node.value);
while (!s.isEmpty()){
Node n=s.pop();//不能pop的时候输出,因为pop过的节点可能被重新压入后再次pop
for(Node next:n.nexts){
if(!hs.contains(next)){
s.add(n);
s.add(next);
hs.add(next);
System.out.println(next.value);
break;
}
}
}
}
}
5、拓扑排序:
package learn;
import java.util.*;
public class TopologySort {
public static List<Node> sort(Graph graph) {
HashMap<Node,Integer> hs=new HashMap<>();//记录node的剩余入度
//入度为0的进入队列 供选择输出
Queue<Node> q=new LinkedList<>();
List<Node> result=new ArrayList<>();//将最终排序结果放入result
//.values获取所有键值对象
for(Node node:graph.nodes.values()){
hs.put(node,node.in);
if(node.in==0){
q.add(node);
}
}
while (!q.isEmpty()){
Node n=q.poll();
result.add(n);
for(Node next:n.nexts){
hs.put(next,hs.get(next)-1);
if(hs.get(next)==0){
q.add(next);
}
}
}
return result;
}
}
6、最小生成树:
(1)Kruskal: 加边,判断一边的两点是否在一个同一个集合中
package learn;
import java.util.*;
public class Kruskal {
//定制一个集合,实现判断是否在同一个集合,合并两点所属的集合
public static class MySets {
public HashMap<Node, List<Node>> hs;
public MySets(List<Node> nodes) {
for (Node n : nodes) {//将每个点加入不同的集合,各成分支
List<Node> l = new ArrayList<>();
l.add(n);
hs.put(n, l);
}
}
public boolean isSameSet(Node from,Node to){
List<Node> l1=hs.get(from);
List<Node> l2=hs.get(to);
return l1==l2;
}
public void union(Node from,Node to) {
List<Node> l1=hs.get(from);
List<Node> l2=hs.get(to);
//将l2中的点并入l1,并修改l2中的点在map中对应集合为l1
for(Node n:l2){
l1.add(n);
hs.put(n,l1);
}
}
}
public static class EdgeComparator implements Comparator<Edge> {
public int compare(Edge o1,Edge o2){
return o1.weight-o2.weight;
}
}
public static Set<Edge> kruskalMST(Graph graph) {
MySets ms=new MySets((List<Node>) graph.nodes.values());//类型转化
PriorityQueue<Edge> pq=new PriorityQueue<>(new EdgeComparator());//小根堆
Set<Edge> result=new HashSet<>();
for (Edge e:graph.edges){
pq.add(e);
}
while (!pq.isEmpty()){
Edge edge=pq.poll();
if(!ms.isSameSet(edge.from,edge.to)){
result.add(edge);
ms.union(edge.from,edge.to);
}
}
return result;
}
}
(2)Prim: 加点
package learn;
import java.util.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
public class Prim {
public static class EdgeComparator implements Comparator<Edge>{
public int compare(Edge o1,Edge o2){
return o1.weight-o2.weight;
}
}
public static Set<Edge> PrimMST(Graph graph) {
PriorityQueue<Edge> pq=new PriorityQueue<>(new EdgeComparator());//将已经解锁的边放入其中
HashSet<Node> hs=new HashSet<>();//将已经并入的点加入该集合
Set<Edge> result=new HashSet<>();//将结果边放入
for(Node node:graph.nodes.values()){//可能出现所有节点并非连通的状态 类似森林
if(!hs.contains(node)){
hs.add(node);//从该节点起生成一个最小生成树
for(Edge edge:node.edges){
pq.add(edge);
}
while (!pq.isEmpty()){
Edge e= pq.poll();//弹出解锁边中最小的边
Node toNode =e.to;
if(!hs.contains(toNode)){
hs.add(toNode);
result.add(e);
for(Edge nextEdge:toNode.edges){
pq.add(nextEdge);
}
}
}
}
}
return result;
}
}
7、Dijkstra: 单源最短路径
package learn;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
public class Dijkstra {
public static HashMap<Node,Integer> dijkstral(Node head) {
HashMap<Node,Integer> distanceMap=new HashMap<>();//记录从源点出发到node的当前最小距离
HashSet<Node> selectedNodes=new HashSet<>();//已经确定从源点到自身最小距离路径的node,锁定在集合中
distanceMap.put(head,0);//源点到源点距离为0
Node minNode=getMinDistanceAndUnselectedNode(distanceMap,selectedNodes);//找到不在锁定节点中,且所有路径中,达到该节点是最短的节点
while (minNode!=null){
int distance=distanceMap.get(minNode);
for (Edge edge : minNode.edges) {
Node toNode = edge.to;
//if (!selectedNodes.contains(toNode)) {//此if判断可有可无
if (!distanceMap.containsKey(toNode)) {
distanceMap.put(toNode, distance + edge.weight);
} else {
distanceMap.put(toNode, Math.min(distanceMap.get(toNode), distance + edge.weight));
}
}
//}
selectedNodes.add(minNode);
minNode=getMinDistanceAndUnselectedNode(distanceMap,selectedNodes);
}
return distanceMap;
}
public static Node getMinDistanceAndUnselectedNode(HashMap<Node,Integer> d,HashSet<Node> s){
Node minNode=null;
int minDistance=Integer.MAX_VALUE;
for(Entry<Node,Integer> entry:d.entrySet()){
Node node=entry.getKey();
if(!s.contains(node)){//当节点都在s中时,无法进入if中,minNode最终会等于null
int distance=entry.getValue();
if(distance<minDistance){
minNode=node;
minDistance=distance;
}
}
}
return minNode;
}
}