图结构
构建
public class Graph {
public HashMap<Integer,Node> nodes;
public HashSet<Edge> edges;
public Graph() {
nodes = new HashMap<Integer, Node>();
edges = new HashSet<Edge>();
}
}
public class Node {
public int value;
public int in;
public int out;
public ArrayList<Node> nexts;
public ArrayList<Node> edges;
public Node(int value) {
this.value = value;
in = 0;
out = 0;
nexts = new ArrayList<>();
edges = new ArrayList<>();
}
}
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;
}
}
转换
public static Graph creatGraph(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 weitht = 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(weitht,fromNode,toNode);
fromNode.nexts.add(toNode);
fromNode.out++;
toNode.in++;
fromNode.edges.add(newEdge);
graph.edges.add(newEdge);
}
return graph;
}
遍历
图的宽度优先遍历
1,利用队列实现
2,从源节点开始依次按照宽度进队列,然后弹出
3,每弹出一个点,把该节点所有没有进过队列的邻接点放入队列
4,直到队列变空
//宽度优先遍历
public static void bfs(Node node){
if (node == null) return;
Queue<Node> queue = new LinkedList<>();
HashSet<Node> set = new HashSet<>();
queue.add(node);
set.add(node);
while (!queue.isEmpty()){
Node cur = queue.poll();
System.out.println(cur.value);
for (Node next : cur.nexts) {
if (!set.contains(next)){
set.add(next);
queue.add(node);
}
}
}
}
广度优先遍历
1,利用栈实现
2,从源节点开始把节点按照深度放入栈,然后弹出
3,每弹出一个点,把该节点下一个没有进过栈的邻接点放入栈
4,直到栈变空
//深度优先遍历
public static void dfs(Node node){
if (node == null) return;
Stack<Node> stack = new Stack<>();
HashSet<Node> set = new HashSet<>();
stack.add(node);
set.add(node);
System.out.println(node.value);
while (!stack.isEmpty()){
Node cur = stack.pop();
for (Node next : cur.nexts) {
if (!set.contains(next)){
stack.push(cur);
stack.push(next);
set.add(node);
System.out.println(next.value);
break;
}
}
}
}
拓扑排序
入度为0的点
//拓扑排序
public static List<Node> sortedTopology(Graph graph){
//key 某一个node
//value 剩余的入度
HashMap<Node,Integer> inMap = new HashMap<>();
//入度为0的点可以进入这个队列
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> res = new ArrayList<>();
while (!zeroInQueue.isEmpty()){
Node cur = zeroInQueue.poll();
res.add(cur);
for (Node next : cur.nexts) {
inMap.put(next,inMap.get(next)-1);//入度-1
if (inMap.get(next) == 0){
zeroInQueue.add(next);
}
}
}
return res;
}
最小生成树
kruskal算法(无向图)
适用范围:要求无向图
从最小的边开始,如果加上没有形成环就加上,如果形成环就不加
public static class MySet{
public HashMap<Node,List<Node>> setMap;
public MySet(List<Node> nodes){
for (Node node : nodes) {
List<Node> set = new ArrayList<>();
set.add(node);
setMap.put(node,set);
}
}
public boolean isSameSet(Node from,Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
return fromSet == toSet;
}
public void union(Node from, Node to){
List<Node> fromSet = setMap.get(from);
List<Node> toSet = setMap.get(to);
for (Node tonode : toSet) {
fromSet.add(tonode);
setMap.put(tonode,fromSet);
}
}
}
prim算法(无向图)
适用范围:要求无向图
//prim算法(无向图)
public static Set<Edge> primMst(Graph graph){
PriorityQueue<Edge> priorityQueue = new PriorityQueue<>(new EdgeComparator());
HashSet<Node> set = new HashSet<>();
Set<Edge> res = new HashSet<>();
for (Node node : graph.nodes.values()) {
if (!set.contains(node)){
set.add(node);
for (Edge edge : node.edges) {//由一个点,解锁它相邻的边
priorityQueue.add(edge);
}
while (!priorityQueue.isEmpty()){
Edge edge = priorityQueue.poll();//弹出最小的边
Node tonode = edge.to;//可能是一个新的点
if (!set.contains(tonode)){ //如果是新的点 重复的点就跳过了
set.add(tonode);
res.add(edge);
for (Edge nextedge : tonode.edges) {
priorityQueue.add(nextedge);
}
}
}
}
}
return res;
}
=================
private static class EdgeComparator implements Comparator<Edge> {
@Override
public int compare(Edge o1, Edge o2) {
return o1.weight - o2.weight;
}
}
Dijkstra算法
适用范围:可以有权值为负数的边 但是不能有累加和为负数的环
单元最短路径
//Dijkstra算法
public static HashMap<Node,Integer> dijkstra(Node head){
//从head出发到所有点的最小距离
// Key:从head出发到key
//value:从head出发到key的最小值
//如果在表中,没有T的记录,含义是从head出发到T这个点的距离为正无穷
HashMap<Node,Integer> distanceMap = new HashMap<>();
distanceMap.put(head,0);
//已经求过的点,存在selectedNodes中
HashSet<Node> selectedNode = new HashSet<>();
Node minNode = getMinDistanceAndUnseLectedNode(distanceMap,selectedNode);
while (minNode != null){
int distance = distanceMap.get(minNode);
for (Edge edge : minNode.edges) {
Node toNode = edge.to;
if (!distanceMap.containsKey(toNode)){
distanceMap.put(toNode,distance+edge.weight);
}
distanceMap.put(edge.to,Math.min(distanceMap.get(toNode),
distance+ edge.weight));
}
selectedNode.add(minNode);
minNode = getMinDistanceAndUnseLectedNode(distanceMap,selectedNode);
}
return distanceMap;
}
private static Node getMinDistanceAndUnseLectedNode(HashMap<Node, Integer> distanceMap, HashSet<Node> touchedNode) {
Node minNode = null;
int minDistance = Integer.MIN_VALUE;
for (Map.Entry<Node, Integer> entry : distanceMap.entrySet()) {
Node node = entry.getKey();
int distancd = entry.getValue();
if(!touchedNode.contains(node) && distancd < minDistance){
minNode = node;
minDistance = distancd;
}
}
return minNode;
}