有方向图:
我们正在为它添加节点和边缘:
然后删除其他一些(通过算法,这里没关系):
我曾尝试在F#中做到这一点,但由于我的经验不足,我无法选择正确的架构决策。
open System.Collections.Generic
type Node = Node of int
type OGraph(nodes : Set<Node>,
edges : Dictionary<Node * int, Node>) =
member this.Nodes = nodes
member this.Edges = edges
let nodes = set [Node 1; Node 2; Node 3]
let edges = Dictionary<Node * int, Node>()
Array.iter edges.Add [|
(Node 1, 10), Node 2;
(Node 2, 20), Node 3;
|]
let myGraph = OGraph(nodes, edges)
myGraph.Nodes.Add (Node 4)
myGraph.Edges.Add ((Node 2, 50), Node 4)
myGraph.Edges.Remove (Node 2, 20)
myGraph.Nodes.Remove (Node 3)
如何添加空节点?我的意思是,它可能是3或4甚至100500.如果我们添加没有数字的节点,那么我们如何使用它来创建边缘? myGraph.Edges.Add ((Node 2, 50), ???)
在命令式范例中,由于使用了命名引用和Null,它很简单,我们可以创建Node newNode = new Node()
然后使用此引用newNode
,但似乎在F#中这是一个不好的做法
我应该指定单独的类型Node和Edge还是使用简单类型?或者可能是其他代表,更复杂?
最好使用常见的.NET可变集合(HashSet,Dictionary等),或特殊的F#集合(Set,Map等)?如果集合很大,那么每次应该更改整个集合时,在性能方面是可以接受的吗?
答案 0 :(得分:3)
图表本身很容易建模。您可以这样定义:
type Graph = { Node : int option; Children : (int * Graph) list }
如果愿意,你可以使用类型别名或自定义类型而不是原始int
值来修饰它,但这是基本的想法。
您可以对OP中描绘的三个图形进行建模,如下所示。我使用的格式看起来很冗长,但我故意用这种方式格式化值,以使结构更清晰;如果您愿意,可以用更紧凑的形式写出值。
let x1 =
{
Node = Some 1;
Children =
[
(
10,
{
Node = Some 2;
Children =
[
(
20,
{
Node = Some 3;
Children = []
}
)
]
}
)
]
}
let x2 =
{
Node = Some 1;
Children =
[
(
10,
{
Node = Some 2;
Children =
[
(
20,
{
Node = Some 3;
Children = []
}
);
(
50,
{
Node = None;
Children = []
}
)
]
}
)
]
}
let x3 =
{
Node = Some 1;
Children =
[
(
10,
{
Node = Some 2;
Children =
[
(
50,
{
Node = Some 3;
Children = []
}
)
]
}
)
]
}
请注意使用int option
来捕获节点是否有值。
Graph
类型是F#记录类型,并为子项使用F#workhorse list
。这将是我的默认选择,只有在性能成为问题时才会考虑其他数据类型。列表很容易使用。
答案 1 :(得分:0)
如果这些很容易就是正确的: