图---java---黑马

概念

图是由顶点(vertex)和边(edge)组成的数据结构,例如
在这里插入图片描述

该图有四个顶点:A,B,C,D以及四条有向边,有向图中,边是单向的。

有向 vs 无向

如果是无向图,那么边是双向的,下面是一个无向图例子

在这里插入图片描述

是指与该顶点相邻的边的数量
在这里插入图片描述

如上图

  • A,B,C,E,F这几个顶点度数为2
  • D顶点度数为4

有向图中,细分为入度和出度,参考下图
在这里插入图片描述

  • A(2 out / 0 in)
  • B、C、E(1 out / 1 in)
  • D(2 out / 2 in)
  • F(0 out / 2 in)

边可以有权重,代表从源顶点到目标定点的距离、费用、时间或其他度量。

在这里插入图片描述

路径被定义为从一个顶点到另一个顶点的一系列连续边,例如上图中【北京】到【上海】有多条路径

  • 北京 - 上海
  • 北京 - 武汉 - 上海

路径长度

  • 不考虑权重,长度就是边的数量
  • 考虑权重,一般就是权重累加

在有向图中,从一个顶点开始,可以通过若干条有向边返回到该顶点,那么就形成了一个

在这里插入图片描述

图的连通性

如果两个顶点之间存在路径,则这两个顶点是连通的,所有顶点都连通,则改图被称之为连通图,若子图连通,则称为连通分量
在这里插入图片描述

图的表示

如下图,
在这里插入图片描述

邻接矩阵表示为:

	A B C D
A	0 1 1 0
B	1 0 0 1
C	1 0 0 1
D	0 1 1 0

使用邻接表表示

A -> B -> C
B -> A -> D
C -> A -> D
D -> B -> C

有向图
在这里插入图片描述

邻接矩阵表示为:

	A B C D
A	0 1 1 0
B	0 0 0 1
C	0 0 0 1
D	0 0 0 0

使用邻接表表示

A -> B -> C
B -> D
C -> D
D -> empty

图的java实现

在这里插入图片描述

顶点

public class Vertex{String name;List<Edge> edges;public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();}
}

public class Edge {Vertex linked;int weight;public Edge(Vertex linked) {this(linked, 1);}public Edge(Vertex linked, int weight) {this.linked = linked;this.weight = weight;}
}

在这里插入图片描述

java表示

public class Vertex{String name;List<Edge> edges;public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");Vertex v7 = new Vertex("v7");v1.edges = List.of(new Edge(v6, 14), new Edge(v2, 7), new Edge(v3, 9));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));}
}

深度优先遍历

添加属性是否被访问过 visited

public class Vertex{String name;List<Edge> edges;boolean visited = false;	// 是否被访问过public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();}// 使用递归public static void dfs(Vertex vertex) {vertex.visited = true;System.out.println(vertex.name);for(Edges edge : vertex.edges) {if(!edge.linked.visited) {dfs(edge.linked);}}}// 使用栈public static void dfs3(Vertex v) {Stack<Vertex> stack = new Stack<>();stack.push(v);while (!stack.isEmpty()) {Vertex pop = stack.pop();pop.visited = true;System.out.println(pop.getName());for(Edge edge : pop.edges) {if (!edge.linked.visited) {stack.push(edge.linked);}}}}
}

广度优先遍历

添加属性是否被访问过 visited

public class Vertex{String name;List<Edge> edges;boolean visited = false;	// 是否被访问过public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();}// 使用队列public static void dfs2(Vertex vertex) {Queue<Vertex> queue = new Queue<>();queue.offer(vertex);vertex.visitedwhile (!queue.isEmpty()) {Vertex poll = queue.poll();poll.visited = true;System.out.println(poll.getName());for(Edge edge : poll.edges) {if (!edge.linked.visited) {edge.linked.visited = true;queue.offer(edge.linked);}}}}}

拓扑排序

在这里插入图片描述

顶点类中添加属性 inDegree

public class Vertex{String name;List<Edge> edges;int inDegree 		// 入度public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();List<Vertex> graph = new ArrayList<>(List.of(a, b, c, d));// 1.遍历每个顶点得到每个顶点的入度for(Vertex vertex : graph) {for(Edge edge : vertex.edges) {edge.linked.inDegree++;}}// 打印输出for(Vertex vertex : graph) {System.out.printlin(vertex.name +:+ vertex.inDegree);}// 2.将入度为0的顶点加入到队列中Queue<Vertex> queue = new Queue<>();for(Vertex vertex : graph) {if (vetex.inDegree == 0) {queue.offer(vertex);}}//3.不断移除队列头部顶点,且打印输出,将相邻顶点的入度减一,若相邻顶点入度减为0加入到队列中while (!queue.isEmpty()) {Vertex poll = queue.poll();System.out.println(poll.name);for(Edge edge : poll.edges) {edge.linked.inDegree--;if (edge.linked.inDegree == 0) {queue.offer(edge.linked);}}}   }}
拓扑排序检测环

当拓扑排序中有环时,遍历图中的顶点,并不能将全部顶点遍历到

在这里插入图片描述

关于在拓扑排序中检测是否有环,创建 List 集合,在移除队列头部顶点时加入顶点属性 name ,最后将 List 与原集合 graph 比较 size 大小,判断是否有环

public class Vertex{String name;List<Edge> edges;int inDegree; 		// 入度public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();List<Vertex> graph = new ArrayList<>(List.of(a, b, c, d));// 1.遍历每个顶点得到每个顶点的入度for(Vertex vertex : graph) {for(Edge edge : vertex.edges) {edge.linked.inDegree++;}}// 打印输出for(Vertex vertex : graph) {System.out.printlin(vertex.name +:+ vertex.inDegree);}// 2.将入度为0的顶点加入到队列中Queue<Vertex> queue = new Queue<>();for(Vertex vertex : graph) {if (vetex.inDegree == 0) {queue.offer(vertex);}}List<String> list = new ArrayList<>();//3.不断移除队列头部顶点,且打印输出,将相邻顶点的入度减一,若相邻顶点入度减为0加入到队列中while (!queue.isEmpty()) {Vertex poll = queue.poll();// System.out.println(poll.name);list.add(poll.name);for(Edge edge : poll.edges) {edge.linked.inDegree--;if (edge.linked.inDegree == 0) {queue.offer(edge.linked);}}} System.out.println(list.size());System.out.println(graph.size());}}
深度优先搜索

在顶点中添加属性 status ,0 表示未访问,1表示访问中,2访问过

public class Vertex{String name;List<Edge> edges;int inDegree; 		// 入度int status;			// 0 未访问; 1 访问中; 2已访问public Vertex(String name) {this.name = name;}public String getName() {return name;}public static void main(String[] args) {Vertex a = new Vertex("A");Vertex b = new Vertex("B");Vertex c = new Vertex("C");Vertex d = new Vertex("D");a.edges = List.of(new Edge(b), new Edge(c));b.edges = List.of(new Edge(d));c.edges = List.of(new Edge(d));d.edges = List.of();List<Vertex> graph = new ArrayList<>(List.of(a, b, c, d));Stack<String> stack = new Stack<>();// 1.遍历每个顶点得到每个顶点的入度for(Vertex vertex : graph) {dfs(vertex, stack);}System.out.println(stack);}public static void dfs(Vertex vertex, Stack<String> stack) {if (vertex.status == 2) {return;}if (vertex.status == 1) {throw new RuntimeException("有环");}vertex.status = 1;for(Edge edge : vertex.edges) {dfs(edge.linked, stack);}vertex.status = 2;stack.push(vertex.name);}}

迪克斯特拉-单源最短路径算法

在这里插入图片描述

算法描述

  1. 将所有顶带你标记为未访问。创建一个未访问顶点的集合。

  2. 为每个顶点分配一个临时距离值

    • 对于我们的初始顶点,将其设置为零;
    • 对于其它所有顶点,将其设置为无穷大;
  3. 每次选择最小临时距离的未访问顶点,作为新的当前顶点;

  4. 对于当前顶点,遍历其所有未访问的邻居,并更新它们的临时距离为更小

    • 例如,1->6的距离为14,而1->3->6的距离为11,这时将距离更新为11
    • 否则,将保留上次距离值
  5. 当前顶点的邻居处理完后,把它从未访问集合中删除;

    在这里插入图片描述

public class Vertex{String name;List<Edge> edges;int inDegree; 		// 入度int status;			// 0 未访问; 1 访问中; 2已访问int dist = INF;static final INF = Integer.MAX_VALUE;public Vertex(String name) {this.name = name;}public String getName() {return name;}
}
public class Dijkstra {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v6, 14), new Edge(v2, 7), new Edge(v3, 9));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4, v5, v6));dijkstra(graph, v1);}public static void dijkstra(List<Vertex>, Vertex source) {ArrayList<Vertex> list = new ArrayList<>(graph);source.dist = 0;while (!list.isEmpty()) {// 选取当前顶点Vertex curr = chooseMinVertex(list);// 更新当前顶点到邻居的距离updateNeighboursDist(curr, list);// 从集合中移除顶点list.remove(curr);}}public Vertex chooseMinVertex(ArrayList<Vertex> list) {Vertex curr = list.get(0);for(Vertex v : list) {if (v.dist < curr.dist) {curr = v;}}return curr;}public void updateNeighboursDist(Vertex curr, ArrayList<Vertex> list) {for(Edge edge : curr.edges) {if (list.contains(edge.linked)) {int dist = curr.dist + edge.weight;if (dist< edge.linked.dist) {edge.linked.dist = dist;}    }} }
}

算法改进

记录路径

public class Vertex{String name;List<Edge> edges;int inDegree; 		// 入度int status;			// 0 未访问; 1 访问中; 2已访问int dist = INF;Vertex pre = null;static final INF = Integer.MAX_VALUE;public Vertex(String name) {this.name = name;}public String getName() {return name;}
}
public class Dijkstra {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v6, 14), new Edge(v2, 7), new Edge(v3, 9));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4, v5, v6));dijkstra(graph, v1);}public static void dijkstra(List<Vertex> graph, Vertex source) {ArrayList<Vertex> list = new ArrayList<>(graph);source.dist = 0;while (!list.isEmpty()) {// 选取当前顶点Vertex curr = chooseMinVertex(list);// 更新当前顶点到邻居的距离updateNeighboursDist(curr, list);// 从集合中移除顶点list.remove(curr);// 或者使用visited作为是否被访问的条件, 更新距离时,不需要传入list参数// curr.visited = true;}for(Vertex v : graph) {System.out.println(v.name + " " + v.dist + " " + (v.pre != null ? v.pre : null));}}public Vertex chooseMinVertex(ArrayList<Vertex> list) {Vertex curr = list.get(0);for(Vertex v : list) {if (v.dist < curr.dist) {curr = v;}}return curr;}public void updateNeighboursDist(Vertex curr, ArrayList<Vertex> list) {for(Edge edge : curr.edges) {if (list.contains(edge.linked)) {int dist = curr.dist + edge.weight;if (dist< edge.linked.dist) {edge.linked.dist = dist;edge.linked.pre = curr; }    }} }
}

优化改进

采用优先级队列存储顶点,使用最小堆改写选择最小距离顶点

public class Dijkstra {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v6, 14), new Edge(v2, 7), new Edge(v3, 9));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4, v5, v6));dijkstra(graph, v1);}public static void dijkstra(List<Vertex> graph, Vertex source) {PriorityQueue<Vertex> queue = new PriorityQueue<>(Comparator.comparingInt(v -> v.dist));source.dist = 0;for(Vertex v : graph) {queue.offer(v);}while (!queue.isEmpty()) {// 选取当前顶点Vertex poll = queue.poll();// 更新当前顶点到相邻顶点的距离if (!curr.visited) {updateNeighboursDist(poll, queue);    poll.visited = true;}// 移除顶点queue.poll();}for(Vertex v : graph) {System.out.println(v.name + " " + v.dist + " " + (v.pre != null ? v.pre : null));}}public void updateNeighboursDist(Vertex curr, PriorityQueue<Vertex> queue) {for(Edge edge : curr.edges) {if (!edge.linked.visited) {int dist = curr.dist + edge.weight;if (dist< edge.linked.dist) {edge.linked.dist = dist;edge.linked.pre = curr; queue.offer(edge.linked);}    }} }
}

不能处理负边情况

Bellman-Ford算法

单源最短路径算法

可以处理负边
在这里插入图片描述

public class BellmanFord{public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v3, 1), new Edge(v2, 2));v2.edges = List.of(new Edge(v3, 2));v3.edges = List.of(new Edge(v4, 1));v4.edges = List.of();List<Vertex> graph = List.of(List.of(v1, v2, v3, v4));bellmanFord(graph, v1);}public void bellmanFord(List<Vertex> graph, Vertex source) {source.dist = 0;for(int i = 0; i < graph.size() - 1; i++) {for(Vertex v : graph) {for(Edge e : v.edges) {if (v.list != Integer.MAX_VALUE && v.dist + e.weight < e.linked.list) {e.linke.dist = v.dist + e.weight;e.linked.pre = v;}}}}for(Vertex v : graph) {System.out.println(v + " " + (v != null ? v.name : null));}}
}

Floyd-Warshall

多源最短路径算法

可以处理 负边,但是不能处理 负环
在这里插入图片描述

使用二维表格记录顶点到顶点的距离
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

public class Vertex{String name;List<Edge> edges;int inDegree; 		// 入度int status;			// 0 未访问; 1 访问中; 2已访问int dist = INF;Vertex pre = null;static final INF = Integer.MAX_VALUE;public Vertex(String name) {this.name = name;}public String getName() {return name;}// 重写hashcode和equals@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) return false;Vertex vertex = (Vertex) o;return Object.equals(name, vertex.name);}@Overridepublic int hashCode() {return name != null ? name.hashcode() : 0;}
}
public class FloydWarshall{public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v3, -2));v2.edges = List.of(new Edge(v3, 3), new Edge(v1, 4));v3.edges = List.of(new Edge(v4, 2));v4.edges = List.of(new Edge(v2, -1));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4));floydWarshall(graph, v1);}public void floydWarshall(List<Vertex> graph, Vertex source) {int size = graph.size();int[][] dist = new int[size][size];// 初始化dist,将外层循环顶点与内层循环顶点相比较,若相等则初始化为0,否则为无穷大for(int i = 0; i < size; i++) {Vertex v = graph.get(i);Map<Vertex, Integer> map = v.edges.stream().collect(Collectors.toMap(e -> e.linked, e ->weight));for(int j = 0; j < size; j++) {Vertex u = graph.get(j);if (v == u) {dist[i][j] = 0;} else {dist[i][j] = map.getOrDefault(u, Integer.MAX_VALUE);}}}print(dist);// 看能否借路是否能到达其他顶点for(int k = 0; k < size; k++) {for(int i = 0; i < size; i++) {for(int j = 0; j < size; j++) {if (dist[i][k] != Integer.MAX_VALUE && dist[k][j] != Integer.MAX_VALUE && dist[i][k] + dist[k][j] < dist[i][j]) {dist[i][j] = dist[i][k] + dist[k][j];}}}print(dist);}}public void print(int[][] dist){System.out.println("----------------");for(int[] row : dist) {System.out.println(Arrays.stream(row).boxed().map(x -> x == Integer.MAX_VALUE ? "♾️" : String.valueOf(x)).map(s -> String.format("%2s", s)).collect(Collectors.joining(",", "[", "]")));}}
}

优化算法

使用二维数组记录当前顶点从哪个顶点过来的

public class FloydWarshall{public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");v1.edges = List.of(new Edge(v3, -2));v2.edges = List.of(new Edge(v3, 3), new Edge(v1, 4));v3.edges = List.of(new Edge(v4, 2));v4.edges = List.of(new Edge(v2, -1));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4));floydWarshall(graph, v1);}public void floydWarshall(List<Vertex> graph, Vertex source) {int size = graph.size();int[][] dist = new int[size][size];Vertex[][] pre = new Vertex[size][size];// 初始化dist,将外层循环顶点与内层循环顶点相比较,若相等则初始化为0,否则为无穷大for(int i = 0; i < size; i++) {Vertex v = graph.get(i);Map<Vertex, Integer> map = v.edges.stream().collect(Collectors.toMap(e -> e.linked, e ->weight));for(int j = 0; j < size; j++) {Vertex u = graph.get(j);if (v == u) {dist[i][j] = 0;} else {dist[i][j] = map.getOrDefault(u, Integer.MAX_VALUE);pre[i][j] = map.get(u) != null ? v : null;}}}print(dist);// 看能否借路是否能到达其他顶点for(int k = 0; k < size; k++) {for(int i = 0; i < size; i++) {for(int j = 0; j < size; j++) {if (dist[i][k] != Integer.MAX_VALUE && dist[k][j] != Integer.MAX_VALUE && dist[i][k] + dist[k][j] < dist[i][j]) {dist[i][j] = dist[i][k] + dist[k][j];pre[i][j] = pre[k][j];}}}print(dist);}print(pre);for(int i = 0; i < size; i++) {for(int j = 0; j < size; j++) {path(pre, graph, i, j);}}}public void print(int[][] dist){System.out.println("----------------");for(int[] row : dist) {System.out.println(Arrays.stream(row).boxed().map(x -> x == Integer.MAX_VALUE ? "♾️" : String.valueOf(x)).map(s -> String.format("%2s", s)).collect(Collectors.joining(",", "[", "]")));}}static void path(Vertex[][] pre, List<Vertex> graph, int i, int j) {LinkedList<String> stack = new LinkedList<>();System.out.println("[" + graph.get(i).name + "," + graph.get(j).name + "]");stack.push(graph.get(j).name);while(i != j) {Vertex vertex = pre[i][j];stack.push(vertex.name);j = graph.indexOf(vertex);}System.out.println(stack);}
}

判断负环

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

主对角线上出现负值, 则可以证明存在负环

最小生成树

顶点为核心,每次找到相邻顶点的最小距离,依次处理顶点 ,更新距离。
在这里插入图片描述

在这里插入图片描述

Prim算法

与迪克斯拉算法相似

public class Dijkstra {public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");v1.edges = List.of(new Edge(v6, 14), new Edge(v2, 7), new Edge(v3, 9));v2.edges = List.of(new Edge(v4, 15));v3.edges = List.of(new Edge(v4, 11), new Edge(v6, 2));v4.edges = List.of(new Edge(v5, 6));v5.edges = List.of();v6.edges = List.of(new Edge(v5, 9));List<Vertex> graph = List.of(List.of(v1, v2, v3, v4, v5, v6));dijkstra(graph, v1);}public static void dijkstra(List<Vertex> graph, Vertex source) {ArrayList<Vertex> list = new ArrayList<>(graph);source.dist = 0;while (!list.isEmpty()) {// 选取当前顶点Vertex curr = chooseMinVertex(list);// 更新当前顶点到邻居的距离updateNeighboursDist(curr);// 从集合中移除顶点list.remove(curr);// 或者使用visited作为是否被访问的条件, 更新距离时,不需要传入list参数curr.visited = true;}for(Vertex v : graph) {System.out.println(v.name + " " + v.dist + " " + (v.pre != null ? v.pre : null));}}public Vertex chooseMinVertex(ArrayList<Vertex> list) {Vertex curr = list.get(0);for(Vertex v : list) {if (v.dist < curr.dist) {curr = v;}}return curr;}public void updateNeighboursDist(Vertex curr) {for(Edge edge : curr.edges) {if (!edge.linked.visited) {int dist = edge.weight;if (dist< edge.linked.dist) {		// 这是与迪克斯拉算法的区别edge.linked.dist = dist;edge.linked.pre = curr; }    }} }
}

Kruskal克鲁斯卡尔算法

为核心 ,逐一处理每条边得到最后的最小生成树

在这里插入图片描述

public class Kruskal{static class Edge implements Comparable<Edge> {List<Vertex> vertices;int start;int end;int weight;public Edge(List<Vertex> vertices, int satrt, int end, int weight) {this.vertices = vertices;this.start = start;this.end = end;this.weight = weight;}public Edge(int start, int end, int weight) {this.start = start;this.end = end;this.weight = weight;}@Overridepublic int compareTo(Object o) {return Integer.compare(this.weight, o.weight);}@OVerridepublic void toString() {return vertices.get(start).name + "<->" + vertices(end).name}}public static void main(String[] args) {Vertex v1 = new Vertex("v1");Vertex v2 = new Vertex("v2");Vertex v3 = new Vertex("v3");Vertex v4 = new Vertex("v4");Vertex v5 = new Vertex("v5");Vertex v6 = new Vertex("v6");Vertex v7 = new Vertex("v7");List<Vertex> vertices = List.of(List.of(v1, v2, v3, v4, v5, v6, v7));PriorityQueue<Edge> queue = new PriorityQueue<>(List.of(new Edge(vertices, 0, 1, 2),new Edge(vertices, 0, 2, 4),new Edge(vertices, 0, 3, 1),new Edge(vertices, 1, 3, 3),new Edge(vertices, 1, 4, 10),new Edge(vertices, 2, 3, 2),new Edge(vertices, 2, 5, 5),new Edge(vertices, 3, 4, 7),new Edge(vertices, 3, 5, 8),new Edge(vertices, 3, 6, 4),new Edge(vertices, 4, 6, 6),new Edge(vertices, 5, 6, 1)));kruskal(vertices.size(), queue);}public void kruskal(int size, PriorityQueue<Edge> queue) {List<Edge> list = new ArrayList<>();DisjoinSet set = new DisjoinSet(size);while (list.size() < size - 1) {Edge poll = queue.poll();int i = set.find(poll.start);int j = set.find(poll.end);if (i != j) {		// 不相交list.add(poll);set.union(poll);}}for(Edge edge : list) {System.out.println(edge);}}
}

并查集

不相交集合

在这里插入图片描述

pubic class DisjoinSet{int[] s;public DisjoinSet(int size) {s = new int[size];for(int i = 0; i < size; i++) {s[i] = i;}}// find 找的是老大public int find(int x) {if(x == s[x]) {return x;}return find(s[x]);}// 两个集合相交,即选出新老大,x, y是原老大索引public void union(int x, int y) {s[y] = x;}public void toString() {return Arrays.toString();}public static void main(String[] args) {DisjoinSet set = new DisjoinSet(7);System.out.println(set);int i = set.find(0);int j = set.find(3);System.out.println("老大分别是:" + i + " " + j);if (i != j) {set.union(i, j);System.out.println(set);}}
}

路径压缩

pubic class DisjoinSet{int[] s;public DisjoinSet(int size) {s = new int[size];for(int i = 0; i < size; i++) {s[i] = i;}}// find 找的是老大---------优化:路径压缩public int find(int x) {if(x == s[x]) {return x;}return s[x] = find(s[x]);}// 两个集合相交,即选出新老大,x, y是原老大索引public void union(int x, int y) {s[y] = x;}public void toString() {return Arrays.toString();}public static void main(String[] args) {}
}

UnionBySize

pubic class DisjoinSet{int[] s;int[] size;public DisjoinSet(int size) {s = new int[size];this.size = new int[size];for(int i = 0; i < size; i++) {s[i] = i;this.size[i] = 1;}}// find 找的是老大---------优化:路径压缩public int find(int x) {if(x == s[x]) {return x;}return s[x] = find(s[x]);}// 两个集合相交,即选出新老大,x, y是原老大索引public void union(int x, int y) {/**if (size[x] > size[y]) {s[y] = x;size[x] = size[y] + size[x];		// 更新元素个数    } else {s[x] = y;size[y] = size[y] + size[x];}**/// if (size[y] > size[x]) {int temp = y;y = x;x = temp;}s[y] = x;size[x] = size[y] + size[x];		// 更新元素个数    }public void toString() {return "内容:" + Arrays.toString(s) + "\n大小:" + Arrays.toString(size);}public static void main(String[] args) {}
}
public void toString() {return Arrays.toString();
}public static void main(String[] args) {}

}


### UnionBySize```java
pubic class DisjoinSet{int[] s;int[] size;public DisjoinSet(int size) {s = new int[size];this.size = new int[size];for(int i = 0; i < size; i++) {s[i] = i;this.size[i] = 1;}}// find 找的是老大---------优化:路径压缩public int find(int x) {if(x == s[x]) {return x;}return s[x] = find(s[x]);}// 两个集合相交,即选出新老大,x, y是原老大索引public void union(int x, int y) {/**if (size[x] > size[y]) {s[y] = x;size[x] = size[y] + size[x];		// 更新元素个数    } else {s[x] = y;size[y] = size[y] + size[x];}**/// if (size[y] > size[x]) {int temp = y;y = x;x = temp;}s[y] = x;size[x] = size[y] + size[x];		// 更新元素个数    }public void toString() {return "内容:" + Arrays.toString(s) + "\n大小:" + Arrays.toString(size);}public static void main(String[] args) {}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/458226.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

aarch64-opencv341交叉编译,并在arm上部署helloopencv

背景 当需要在jetson xavier nx或者rk 3562等平台上开发关于视觉检测的工程时&#xff0c;由于arm板子资源不足或者不能联网等原因&#xff0c;通常在虚拟机上利用交叉编译器编译得到可执行程序&#xff0c;然后部署到arm板上。 aarch64-opencv341交叉编译 ubuntu虚拟机中先…

【Linux】环境下升级redis

一、摘要 最近漏洞扫描服务器发现&#xff0c;Redis 缓冲区溢出漏洞(CVE-2024-31449)&#xff0c;解决办法redis更新到6.2.16、7.2.6或7.4.1及以上版本。 二、漏洞描述 漏洞描述&#xff1a;经过身份验证的用户可能会使用特制的 Lua 脚本来触发位库中的堆栈缓冲区溢出&#…

Kaggle比赛复盘

Kaggle - LLM Prompt Recovery 解决方案报告 比赛背景/目标 大型语言模型&#xff08;Large Language Models&#xff0c;LLMs&#xff09;通常被用于改写或对文本进行风格修改。本次Kaggle竞赛的目标是根据给定的改写文本&#xff0c;还原用于将原始文本转换为改写文本的LLM…

MetaArena推出《Final Glory》:引领Web3游戏技术新风向

随着区块链技术的日益成熟&#xff0c;Web3游戏成为了游戏产业探索的新方向&#xff0c;将去中心化经济与虚拟世界结合在一起&#xff0c;形成了一个全新的生态体系。然而&#xff0c;尽管Web3游戏展示了令人兴奋的可能性&#xff0c;但其背后的技术障碍依旧严峻&#xff0c;特…

Android Activity SingleTop启动模式使用场景

通知栏 当用户点击通知栏中的通知时,可以使用单顶启动模式来打开对应的活动,并确保只有一个实例存在。 简单集成极光推送 创建应用 获取appkey参数 切换到极光工作台 极光sdk集成 Project 根目录的主 gradle 配置 Module 的 gradle 配置 Jpush依赖配置 配置推送必须…

华为原生鸿蒙操作系统:我国移动操作系统的新篇章

华为原生鸿蒙操作系统&#xff1a;我国移动操作系统的新篇章 引言 在移动操作系统领域&#xff0c;苹果iOS和安卓系统一直占据主导地位。然而&#xff0c;随着华为原生鸿蒙操作系统的正式发布&#xff0c;这一格局正在发生深刻变化。作为继苹果iOS和安卓系统后的全球第三大移动…

Python酷库之旅-第三方库Pandas(170)

目录 一、用法精讲 781、pandas.arrays.IntervalArray.contains方法 781-1、语法 781-2、参数 781-3、功能 781-4、返回值 781-5、说明 781-6、用法 781-6-1、数据准备 781-6-2、代码示例 781-6-3、结果输出 782、pandas.arrays.IntervalArray.overlaps方法 782-1…

shodan3,vnc空密码批量连接,ip历史记录查找

shodan语法&#xff0c;count&#xff0c;honeyscore count 今天带大家继续学习shodan&#xff0c;今天会带大家学一学这个count命令&#xff0c;再学学其他小命令好其实关键命令也没那么多&#xff0c;就是很方便记忆一下就学会了这样子。 shodan count "/x03/x00/x00…

Docker下载途径

Docker不是Linux自带的&#xff0c;需要我们自己安装 官网&#xff1a;https://www.docker.com/ 安装步骤&#xff1a;https://docs.docker.com/engine/install/centos/ Docker Hub官网(镜像仓库)&#xff1a;https://hub.docker.com/ 在线安装docker 先卸载旧的docker s…

JMeter实战之——模拟登录

本篇介绍使用JMeter 如何对需要登录的站点进行压力测试。 基本Session验证的机制 使用session进行请求验证的机制是一种常见的Web应用认证方式。 该认证方式的主要内容如下&#xff1a; 一、登录过程 用户输入&#xff1a;用户在登录页面输入用户名和密码。发送请求&#x…

JDBC: Java数据库连接的桥梁

什么是JDBC&#xff1f; Java数据库连接&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java提供的一种API&#xff0c;允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口&#xff0c;开发者可以利用这些接口执行SQL语句、处理结果集…

XQT_UI 组件|02| 按钮 XPushButton

XPushButton 使用文档 简介 XPushButton 是一个自定义的按钮类&#xff0c;基于 Qt 框架构建&#xff0c;提供了丰富的样式和功能选项。它允许开发者轻松创建具有不同外观和行为的按钮&#xff0c;以满足用户界面的需求。 特性 颜色设置&#xff1a;支持多种颜色选择。样式设…

Python之Excel自动化处理(三)

一、Excel数据拆分-xlrd 1.1、代码 import xlrd from xlutils.copy import copydef get_data():wb xlrd.open_workbook(./base_data/data01.xlsx)sh wb.sheet_by_index(0){a: [{},{},{}],b:[{},{},{}],c:[{},{},{}],}all_data {}for r in range(sh.nrows):d {type:sh.cell…

css知识点梳理2

1. 选择器拓展 在 CSS 中&#xff0c;可以根据选择器的类型把选择器分为基础选择器和复合选择器&#xff0c;复合选择器是建立在基础选择器之上&#xff0c;对基本选择器进行组合形成的。 ​ 复合选择器是由两个或多个基础选择器&#xff0c;通过不同的方式组合而成的&#xf…

《a16z : 2024 年加密货币现状报告》解析

加密社 原文链接&#xff1a;State of Crypto 2024 - a16z crypto译者&#xff1a;AI翻译官&#xff0c;校对&#xff1a;翻译小组 当我们两年前第一次发布年度加密状态报告的时候&#xff0c;情况跟现在很不一样。那时候&#xff0c;加密货币还没成为政策制定者关心的大事。 比…

服务器数据恢复—EXT3文件系统下邮件数据被误删的数据恢复案例

服务器数据恢复环境&#xff1a; 邮件服务器中有一组由8块盘组成的RAID5阵列, 上层是Linux操作系统EXT3文件系统。 服务器故障&#xff1a; 由于误删除导致文件系统中的邮件数据丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有硬盘做好标记后取出&#xff0c;硬…

Python实现Android设备录屏功能及停止录屏功能

1、功能概述&#xff1f; 提供源码下载 之前通过ADB命令实现了实时的录屏功能。但是很遗憾&#xff0c;虽然通过adb命令录屏非常方便&#xff0c;但由于权限限制&#xff0c;无法在安卓系统较高的设备上使用。现选择使用另一开源工具来解决这一问题&#xff0c;并记录使用详细…

pytorh学习笔记——cifar10(六)MobileNet V1网络结构

基础知识储备&#xff1a; 一、深度可分离卷积&#xff08;Depthwise Separable Convolution&#xff09; MobileNet的核心是深度可分离卷积&#xff08;Depthwise Separable Convolution&#xff09;&#xff0c;深度可分离卷积是卷积神经网络&#xff08;CNN&#xf…

Java 基于 poi 和 itextpdf 实现 excel 转 pdf

目录 问题 实现思路 pom Excel2PDFUtil Excel2PDFUtilTest 输出结果 问题 工作中遇到一个需求&#xff0c;需要实现 excel 文件的预览&#xff0c;实现的思路就是将 excel 转成 pdf 文件&#xff0c;上传到文件服务器上得到文件地址&#xff0c;预览时只需要返回 pdf 预…

UHF机械高频头的知识和待学习的疑问

电路图如上所示&#xff1a; 实物开盖清晰图如下&#xff1a; 待学习和弄懂的知识&#xff1a; 这是一个四腔的短路线谐振。分别是输入调谐&#xff0c;放大调谐&#xff0c;变频调谐和本振 第一个原理图输入为75欧&#xff08;应该是面向有同轴线的天线了&#xff09;如下图…