图由点集和边集构成。
有向图有箭头如下下图,无向图无箭头如下图
邻接表,如下图,记录ABCD的直接邻居。
这种结构可以表达所有图,比如有权值的图,如下下图
邻接矩阵法:用一个矩阵来表达上图(有向图,无向图都能表示)
图的题出现,难点在于已经会的算法还要重新实现一遍,因为图的实现方式太多了,但是突然换了一种图表达的方式,coding要变,
解决方法:把图按照自己最爱表达的方式实现所有的算法,作为自己以后遇到所有图问题的模板。
如下图,系统给出一个图,直接套自己实现的那个图的模板
图的表达方式太多了,比如邻接矩阵,邻接表这些。
对于题目给出的图的表达方式,自己只需要写一个两种结构的转化,就不用再重新写一遍算法了,即每次写图的题目的时候写一个接口,把它给的图结构变成自己最喜欢的那种图结构(自己喜欢的结构,平时已经用它的实现了所有的算法了),这里只用再求一个结果
图描述
package class06;
import java.util.HashMap;
import java.util.HashSet;
public class Graph {
//图
public HashMap<Integer,Node> nodes;//点集,
//Integer表示key,Node表示实际的点
public HashSet<Edge> edges;//边集
public Graph() {
nodes = new HashMap<>();
edges = new HashSet<>();
}
}
点描述
package class06;
import java.util.ArrayList;
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;
in = 0;
out = 0;
nexts = new ArrayList<>();
edges = new ArrayList<>();
}
}
A有0个入度,2个出度
B的入度1,出度1
C的入度2,出度0
参考下图
参考下图,A的nexts是B和C,B的nexts是C,nexts关注的是发散出去的边直接相邻的点有哪些。public ArrayList<Node> nexts;
C没哟nexts
参考下图:public ArrayList<Edge> edges;//属于我的边有哪些
属于A的边是下图蓝色,属于B的边是下图红色,没有边属于C
边描述
package class06;
//这里表达的是有向边,无向边不用管,无向边就相当于两条有向边拼的
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;
}
}
接口(将用户给的千奇百怪的东西转为自己所熟悉的数据结构)
下述code转换上述结构为熟悉结构
package class06;
public class GraphGenerator {
public static Graph createGraph(Integer[][] matrix) {
Graph graph = new Graph();
for (int i = 0; i < matrix.length; i++) {
//matrix[0][0],边的权值
//matrix[0][1],Node from
//matrix[0][2],Node to
Integer weight = matrix[i][0];
Integer from = matrix[i][1];
Integer to = matrix[i][2];
//上述三行代码换了下顺序,理解意思。就是拿到form,to和权值。
if (!graph.nodes.containsKey(from)) {/
/如果此时的from城市没出现过
//graph里面的nodes是一章HashMap,记录key和对应的Node
//所以可以通过查询from这个key是否存在来判断Node from是否存在
graph.nodes.put(from, new Node(from));//在图的点集中把这个城市新建出来,from这个点加进图里去了。
//new Node(from)先初始化,调用class Node构造函数
}
if (!graph.nodes.containsKey(to)) {//同理to这个城市一样的操作
graph.nodes.put(to, new Node(to));
}
Node fromNode = graph.nodes.get(from);//在点集里面,把from这个实际的点给拿出来
Node toNode = graph.nodes.get(to);//在点集里面,把fto这个实际的点给拿出来
Edge newEdge = new Edge(weight, fromNode, toNode);//根据上述的fromNode和toNode建立新的边
//接下来按照class Node里需要的参数,取得对应value
fromNode.nexts.add(toNode);
fromNode.out++;
toNode.in++;
fromNode.edges.add(newEdge);//新建的边是属于fromNode的edges里,即其拥有的边里
graph.edges.add(newEdge);//newedge放入边集
}
return graph;
}
}
比如将下图这种用户给出的数据结构转为自己熟悉的