所以我需要一些帮助来找到最小生成树的方法。 假设我以邻接列表的形式得到了我的图表:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
第一个字母告诉您正在查看哪个节点,该数字表示与其他任何节点的连接数。例如,A有两个连接 - 一个连接到B和I.之后,字母后面的数字只表示边的权重。 B的重量为12,我的重量为25.所以我原计划将这整个事物表示为一个String数组
叫Graph[8]
。每一行都是数组中的不同插槽。我无法通过Prims或Kruskalls算法找出如何实现这一目标。
答案 0 :(得分:6)
这不是你的问题的直接答案(似乎你正在做功课),但我认为这将有助于你开始。为什么不创建一个更接近您的心理模型并从那里建立的数据结构?
class GraphNode {
final String name;
final List<GraphEdge> adjacentNodes;
public GraphNode(String name) {
this.name = name;
adjacentNodes = new ArrayList<GraphEdge>();
}
public void addAdjacency(GraphNode node, int weight) {
adjacentNodes.add(new GraphEdge(node, weight));
}
}
class GraphEdge {
final GraphNode node;
final int weight;
public GraphEdge(GraphEdge node, int weight) {
this.node = node;
this.weight = weight;
}
}
答案 1 :(得分:2)
假设我的树以邻接列表的形式出现
重要(为了您的理解)请注意,您在这种邻接列表中有一个连接的图,但我认为这只是一个错字。我会建议将其作为编辑,但我只是想让你意识到这一点。 从这些方面可以看出它是图形而不是树的事实:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
这里你已经在A-B-I圈了一个圈子:
A
12/_\25
B 8 I
根据定义拥有一个圆圈意味着它不能是一棵树! 从我提出这个子图的方式中可以看到另外一件事: 边缘有权重,而不是节点。
现在让我们来看看你提供的例子:
A 2 B 12 I 25
B 3 C 10 H 40 I 8
C 2 D 18 G 55
D 1 E 44
E 2 F 60 G 38
F 0
G 1 H 35
H 1 I 35
首先,我们可以看到此邻接列表不正确或已针对您的需求进行了优化。这可以(例如)从行
中看出E 2 F 60 G 38
F 0
此处的第一行显示从E到F的边,但第二行显示F的度数为0,但度数由入射到它的边定义!
这是邻接列表如果是“完整”的样子:
A 2 B 12 I 25
B 4 A 12 C 10 H 40 I 8
C 3 B 10 D 18 G 55
D 2 C 18 E 44
E 3 D 44 F 60 G 38
F 1 E 60
G 3 C 55 E 38 H 35
H 3 B 40 G 35 I 35
我们可以看到很多冗余,因为每个边缘都会出现两次,这就是为什么你的“优化”邻接列表更适合你的需要 - 如果这个'完整'的例子可以做很多无用的检查。 但是,如果您可以确保为代码提供的所有数据都已经“优化”(或者更确切地说是这种格式),那么仅依赖于此。从现在开始,我将把它当作一个给定的。
让我们谈谈您的数据结构。 你当然可以使用你提出的字符串数组,但说实话,我宁愿推荐@ AmirAfghani提出的数据结构。使用他的方法可以使你的工作更轻松(正如他已经指出的那样 - 更接近你的心理表征),甚至更有效(我猜,不要依赖于这个猜测;) )因为你会对字符串执行许多操作。 在Prim的算法后你问的标题,但在你的实际问题中,你说要么是 Prim's还是Kruskal's。我会选择Kruskal,因为他的算法更简单,你似乎同时接受它们。
Kruskal的算法非常简单,基本上是:
尽可能多地重复以下事项:
这就是全部。这真的很简单。 但是我想在这一点上提一件事,我认为它最适合这里:一般没有“最小生成树”,但是“最小生成树”可能有很多,所以你的结果可能会有所不同!
返回您的数据结构!您现在可以看到为什么使用字符串数组作为数据结构是个坏主意。你会对字符串重复许多操作(例如检查每条边的权重), 字符串是不可变的 ,这意味着你不能简单地“扔掉”其中一条边或以任何方式标记其中一条边。 使用不同的方法,您可以将权重设置为-1,甚至删除边缘的条目!
从我所看到的情况来看,我认为你的主要问题是决定边缘是否会导致一个圆圈,对吧? 要做出决定,您可能需要调用深度优先搜索算法并使用其返回值。 基本思想是这样的:从一个节点开始(我将这个节点称为根节点),并尝试找到一条通向所选边缘另一端节点的方法(我将此节点称为目标节点)。 (当然在图中没有这个边缘)
现在,如果此方法返回true
,则此边缘会产生一个圆圈。