gpt4 book ai didi

java - 在 Java 中实现 Prim 的 MST

转载 作者:行者123 更新时间:2023-11-30 10:02:10 25 4
gpt4 key购买 nike

我无法让我的代码遵循第 635 页中 CLRS 的最小生成树 (MST) 示例。我还从字面上实现了 CLRS 的 MST-Prim 伪代码,即

enter image description here

特别是,我使用邻接表实现了下图:enter image description here

所以我实际上有两个问题。第一个是在将节点 b 添加到 MST 之后,我的代码选择作为 PriorityQueue 节点 h 中的下一个元素,而不是节点 c。我不确定 Java 的实现如何在关系的情况下选择元素,所以如果我能做些什么请告知。为了暂时规避这个问题,我修改了边 a-h 的权重为 9。

然后一切都正常运行,直到它在将 f 添加到 MST 之后选择节点 d 而不是 g,我觉得这很奇怪,因为PriorityQueue 显然有 gkey=6

我的实现如下:

import java.util.LinkedList;
import java.util.PriorityQueue;

class Edge{

private Node source;
private Node destination;
private int weight;

public void setSource(Node source) {
this.source = source;
}

public void setDestination(Node destination) {
this.destination = destination;
}

public void setWeight(int weight) {
this.weight = weight;
}

public int getWeight() {
return this.weight;
}

public Node getSource() {
return this.source;
}

public Node getDestination() {
return this.destination;
}

}

class Node implements Comparable<Node>{
private String label;
private LinkedList<Edge> edges;
private int key;
private Node daddy;

Node() {
this.edges = new LinkedList();
}

public void setLabel(String label) {
this.label = label;
}

public void setKey(int key) {
this.key = key;
}

public void setDaddy(Node daddy) {
this.daddy = daddy;
}

public String getLabel() {
return this.label;
}

public int getKey() { return this.key; }

public LinkedList getEdges() {
return this.edges;
}

@Override
public int compareTo(Node o) {
if (this.getKey() > o.getKey()) {
return 1;
}
else if (this.getKey() < o.getKey()) {
return -1;
}
else {
return 0;
}
}
}

public class Graph {

private int numberOfNodes;
private Node[] weightedGraph;

public Graph(int graphV) {

this.numberOfNodes = graphV;
this.weightedGraph = new Node[this.numberOfNodes];
for (int i = 0; i < this.numberOfNodes; i++) {
this.weightedGraph[i] = new Node();
}
}

public void addEdge(String sourceLabel, String destinationLabel, int weight) {

Node sourceNode = null;
Node destinationNode = null;

for (Node node: this.weightedGraph) {
if (node.getLabel().contains(sourceLabel)) {
sourceNode = node;
}
if (node.getLabel().contains(destinationLabel)) {
destinationNode = node;
}
}

Edge e = new Edge();
e.setWeight(weight);
e.setSource(sourceNode);
e.setDestination(destinationNode);
sourceNode.getEdges().add(e);

}

public void minimumSpanningTree(String root) {
Node rootNode = null;
for (Node vertex: this.weightedGraph) {
vertex.setKey(Integer.MAX_VALUE);
vertex.setDaddy(null);
if (vertex.getLabel().contains(root)) {
rootNode = vertex;
}
}

rootNode.setKey(0);

PriorityQueue<Node> nodePriorityQueue = new PriorityQueue<>();

for (Node vertex: this.weightedGraph) {
nodePriorityQueue.add(vertex);
}
int min = 0;
while (!nodePriorityQueue.isEmpty()) {

Node u = nodePriorityQueue.peek();

LinkedList<Edge> uEdges= u.getEdges();
for (Edge e: uEdges) {
Node v = e.getDestination();
int u_vWeight = e.getWeight();
if (nodePriorityQueue.contains(e.getDestination()) && u_vWeight < v.getKey()) {
v.setDaddy(u);
v.setKey(u_vWeight);
}
}
nodePriorityQueue.remove(u);
min += u.getKey();
}

}

public static void main(String[] args) {

Graph graph = new Graph(9);
String[] nodes = new String[9];
nodes[0] = "a";
nodes[1] = "b";
nodes[2] = "c";
nodes[3] = "d";
nodes[4] = "e";
nodes[5] = "f";
nodes[6] = "g";
nodes[7] = "h";
nodes[8] = "i";
int pos = 0;
for (String s: nodes) {
graph.weightedGraph[pos].setLabel(s);
pos += 1;
}

graph.addEdge("a", "b", 4);
graph.addEdge("a", "h", 9);
graph.addEdge("b", "h", 11);
graph.addEdge("b", "c", 8);
graph.addEdge("h", "i", 7);
graph.addEdge("i", "g", 6);
graph.addEdge("c", "f", 4);
graph.addEdge("c", "d", 7);
graph.addEdge("d", "e", 9);
graph.addEdge("d", "f", 14);
graph.addEdge("e", "f", 10);
graph.addEdge("h", "g", 1);
graph.addEdge("c", "i", 2);
graph.addEdge("g", "f", 2);

graph.minimumSpanningTree("a");


}
}

基本上我有三个类,NodeEdgeGraph。我在 Node 中包含了一个 Comparator 以允许 PriorityQueue 根据需要重新排序元素。

我构建图表,调用 minimumSpanningTree,它打印以下 MST:

a
b
c
i
f
d
e
h
g

而不是像我在下面展示的 CLRS 示例中那样执行 a-b-c-i-f-g: enter image description here

我真的不明白为什么它选择节点 d 而不是 gg 显然具有最低键时,通过调试检查priorityQueue 证实了这一点。

非常感谢您的帮助。

最佳答案

我想出了我的问题。事实证明,我构建的邻接表表示中的边是有向的。为了解决这个问题,我只是添加了反向边缘,一切都按预期进行。

而且事实证明,优先级队列在删除其中一个元素时不会更新其元素。根据 SO 上关于优先级队列 (PQ) 未更新的一些其他答案,我从 PQ 中删除并添加了节点,这些节点的键在 for 循环内更新。有人有更好的建议吗? minimumSpanningTree 的更新代码如下:

public void minimumSpanningTree(String root) {

ArrayList<Node> msTree = new ArrayList<>();

Node rootNode = null;
for (Node vertex: this.weightedGraph) {
vertex.setKey(Integer.MAX_VALUE);
vertex.setDaddy(null);
if (vertex.getLabel().contains(root)) {
rootNode = vertex;
}
}

rootNode.setKey(0);

PriorityQueue<Node> nodePriorityQueue = new PriorityQueue<>();

for (Node vertex: this.weightedGraph) {
nodePriorityQueue.add(vertex);
}
int min = 0;
while (!nodePriorityQueue.isEmpty()) {

Node u = nodePriorityQueue.peek();

LinkedList<Edge> uEdges= u.getEdges();
for (Edge e: uEdges) {
Node v = e.getDestination();
int u_vWeight = e.getWeight();
if (nodePriorityQueue.contains(e.getDestination()) && u_vWeight < v.getKey()) {
nodePriorityQueue.remove(v);
v.setDaddy(u);
v.setKey(u_vWeight);
nodePriorityQueue.add(v);
}
}
msTree.add(u);
System.out.println(u.getLabel());
nodePriorityQueue.remove(u);
}

编辑:但是,我在边 a-ha-b 方面遇到了同样的问题。我认为它仍然是 MST,但有没有一种方法可以优先访问节点 b,然后再访问 h? IE。如果优先级队列中有关系,优先考虑具有较低字母数字优先级的键?

关于java - 在 Java 中实现 Prim 的 MST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57129248/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com