Doubly linked data structures in erlang
嗨,我想制作一棵在父子之间保持双向引用的树。但是似乎无法实现,因为当我创建第一个对象时,我没有另一个对象,因此无法对其进行引用。这是一些示例代码。
1 2 3 4 5 6 7 8 9 10 | -record(node,{name,children,root}). main()-> A = #node{name="node-A", children=[B], %variable B is unbound root=nil}, B = #node{name="node-B", children=[], root=A}, Tree = A. |
此问题的另一个示例是实现双向链接列表(http://zh.wikipedia.org/wiki/双向链接列表)
1 2 3 4 5 6 7 8 9 10 | -record(node,{prev,name,next}). main()-> A = #node{prev=nil, name="node-A", next=B}, % variable B is unbound B = #node{prev=A, name="node-B", next=nil}, LinkedList = A. |
有没有一种方法可以实现这种结构。
不,由于所有数据都是不可变的,因此没有直接的方法可以在Erlang中实现双向链接列表。而且即使您可以设置它(您不能设置),您也无法做任何事情,因为所有数据都是不可变的。此处介绍的其他解决方案通过构建以双链表方式运行的数据结构,向您展示了解决此问题的方法。但是不是。
您可以定义类似
的记录
-record(my_node,{leftchild,rightchild,parent,value}。
并将树存储在ets表中,
1 2 |
,然后您可以使用表键作为"指针"来管理链接。
1 2 3 4 5 6 7 8 9 10 11 12 | Root = {make_ref(),#my_node{value=somevalue}} ets:insert(my_tree,Root), A_child = {make_ref(),#my_node{value=othervalue}}, addchild(Root,A_child,left), ... addchild(Parent={Pref,Pval},Child={Cref,Cval},left) -> ets:insert(my_tree,{Pref,Pval#my_node{leftchild=Cref}}), ets:insert(my_tree,{Cref,Cval#my_node{parent=Pref}}); addchild(Parent={Pref,Pval},Child={Cref,Cval},right) -> ets:insert(my_tree,{Pref,Pval#my_node{rightchild=Cref}}), ets:insert(my_tree,{Cref,Cval#my_node{parent=Pref}}). |
但是也许您应该查看更多的" erlang样式"数据表示形式来解决您的问题。如果有多个进程访问树,则我提出的解决方案也存在问题,因为树的更新不是原子的。在这种情况下,您应该使用mnesia,这是ets之上的数据库层,它将为您带来原子事务。
您可以检查如何在ferd的拉链库中实现此操作
当您具有"链接"(例如指针)时,可以创建双链表。在erlang中,您没有此类链接,甚至没有真正的变量,因此无法更改它们。以下是循环列表的一些示例,但应谨慎实施:可以在Erlang中定义循环列表吗?
也许您可以告诉我们为什么需要双重链接树?也许在erlang中有更好的解决方案。
编辑:您可以使用有向图。您的树可以表示为循环图,其中具有从A到B以及从B到A的顶点。具有根节点A以及子B和C的树的示例:
1 2 3 4 5 6 7 8 9 10 | main()-> Tree = digraph:new([cyclic]), A = digraph:add_vertex(Tree,"vertexA"), B = digraph:add_vertex(Tree,"vertexB"), C = digraph:add_vertex(Tree,"vertexC"), digraph:add_edge(Tree, A, B), digraph:add_edge(Tree, B, A), digraph:add_edge(Tree, A, C), digraph:add_edge(Tree, C, A), digraph:get_path(Tree, B, C). |
结果:
如果您确实需要执行类似操作,则可以使用某种ID来引用您的节点。例如
1 2 3 4 5 6 7 8 | A = #node{name="node-A", children=["node-B"], parent=nil}, B = #node{name="node-B", children=[], parent="node-A"}, NodeDict = dict:from_list([{A#node.name, A}, {B#node.name, B}]), Tree = #tree{root=A#node.name, nodes=NodeDict}. |