我正在尝试为图表创建结构。到目前为止,我正在努力弥补我应该如何为边创建一些类。
图表中的边缘可以是
正, 指导,加权(或以上任何一种)。
那么你认为组织这个类的最佳方式是什么,我想创建一个接口IEdge,然后创建类
public interface IEdge{
}
public class DirectedEdge implements IEdge{}
public class WeightedEdge implements IEdge{}
但是现在我遇到了一个问题,它不是很灵活,如果我想要以下内容
public class DirectedWeightedEdge implements IEdge{}
你会如何编码?
答案 0 :(得分:2)
为什么要明确创建边缘?在每个图形实现中,到目前为止,边缘存在于节点对象中。在每个节点中,您需要一组相邻节点 - 如果您需要它们,只需添加一个整数。
方向也很自然地来自(也就是双向图很容易用单向表示)。显然,如果图形足够小,你也可以将它们保存为邻接矩阵 - 这对并行算法来说非常好。但是如果性能很重要,那么我们谈的是完整矩阵不可用的大小。
编辑:评论之后我想我应该澄清一点:使用Edge类来保存关于边缘(颜色,重量)的附加信息很好,但我总是将它用作特定节点的一部分:I.e。像这样的事情 - 在C中我会使用一个结构。
class Node {
List<Edge> children;
class Edge {
int weight;
Color color;
Node dest;
}
}
答案 1 :(得分:2)
这不是OOP练习 - 我的意思是,首先使用逻辑,然后查看模式。有向图和无向图是非常不同的野兽。有向边具有开始和结束,无向有边仅有两个节点。你可以将它们称为开始和结束,以获得一个共同的基础,但是没有定向这样的东西被添加到边缘。
同时,边缘可能有颜色,重量,价格,长度,容量等。您真的想要实施ColoredWeightedPricedHavingLenghtCapacityLimitedEdge
吗?或者你想使用5个装饰器?我希望你不要。
我的第一点是“指向性”并不适合任何模式。您可以使用属性“isDirected”或其他任何东西,也许您根本不需要它,因为大多数图形不会混合不同类型的边缘。因此每个Graph
应该有一个属性。很多时候,一个无向边缘由一对两个有向的边缘代表。
我的第二点是,重量之类的东西一般不应该强行放在边缘。使用Map<IEdge, Double>
作为Graph
的属性可以做得更好。你仍然可以使用像Edge和Node这样的对象,这会阻止它们混淆(在你可能使用它们id
的情况下很容易发生的事情),但是保持它们的属性是外部的。
答案 2 :(得分:1)
我使用了继承和前面提到的装饰模式的混合。
有向和无向边的行为完全不同,它们是强制性的并且是互斥的。因此,它们应该是Edge
接口的唯一两个实现。
然而,权重只是你可以在现有边缘上固定的东西,因此装饰器模式对他们来说是最合适的。
但是要暂时回到原点,取决于共享代码定向和无向边的数量,可能Edge
抽象类比接口更好。当然,“正确”的解决方案是同时拥有:一个接口,由一个抽象类实现,由两个具体类扩展。但在这种情况下,这听起来像过度工程。
答案 3 :(得分:0)
在这里使用装饰器模式可能是合适的: http://en.wikipedia.org/wiki/Decorator_pattern
基本上,您将拥有一个实现IEdge的基类,以及同时实现IEdge接口的DirectedEdgeDecorator和WeightedEdgeDecorator类。 * Decorator类将“包装”基本边缘类并为其添加附加功能。使用此模式,您可以在IEdge上堆叠多个装饰器,一个在另一个上,以不同的方式修改其行为。
答案 4 :(得分:0)
您可以将边缘信息与邻接信息分开。这意味着您不会复制边数据,而是将它们存储在邻接列表中。
public class Node<TEdge> {
class AdjacencyInfo {
Node<TEdge> node;
TEdge edge;
public AdjacencyInfo(Node<TEdge> node, TEdge edge) {
// ....
}
}
bool isDiGraph;
List<AdjacencyInfo> adj;
///.... constructor, other methods
public TEdge ConnectTo(Node<TEdge> node) {
TEdge e = new TEdge();
AdjacencyInfo a0 = new AdjacencyInfo(node, e);
this.adj.Add(a0);
if (!isDiGraph) {
AdjacencyInfo a1 = new AdjacencyInfo(this, e);
node.adj.Add(a1);
}
return e; // return the edge so caller is able to set edge properties (weight, color, etc)
}
}
这样的事情应该有效并且能够清楚地解决定向/非定向问题。我不知道使用Java泛型可以实现多少这一点,因为除了避免容器中的类型转换之外,它们几乎不能用于其他事情,但是如果你需要只能处理加权边缘,那么你可以避免泛型将重量设置为1或任何有意义的。
答案 5 :(得分:-2)
一种类型,有两个属性
type Edge
boolean directed = false;
number weight = 1;