Doubly linked data structures in erlang

旧街凉风 提交于 2019-12-05 02:51:56

问题


Hi I want to make a tree that keeps two-way references between parent and children. But it seems impossible to achive since when I create first object I do not have the other one yet therefore cannot have a reference to it. Here is some sample code.

-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.

Another example to this problem would be implementing a doubly linked list (http://en.wikipedia.org/wiki/Doubly_linked_list)

-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.

Is there a way to implement this kind of structure.


回答1:


You can make doubly linked lists when you have "links" (like pointers). In erlang you don't have such links and you don't have even real variables, you can't change them. Here are some examples for circular lists, but they should be implemented with caution: Can Circular Lists be defined in Erlang?

Maybe you could tell us why you need doubly linked tree? Maybe there is a better solution in erlang.

Edit: You could use digraph. Your tree can be represented as cyclic graph where you have vertices from A to B and from B to A. Example of a tree with root node A and children B and C:

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).

Result: ["vertexB","vertexA","vertexC"]




回答2:


You could inspect how this implemented in ferd's zippers library




回答3:


No, there is no direct way to implement doubly linked lists in Erlang as all data is immutable. And even if you could set it up (which you can't) you couldn't do anything with as all data immutable. The other solutions presented here show you ways of getting around this by building data structures which behave in a doubly linked list fashion. But aren't.




回答4:


If you really need to do something like that, you could use some kind of IDs to refer to your nodes. E.g.

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}.



回答5:


You can define a record like

-record(my_node,{leftchild,rightchild,parent,value}.

and store your tree in an ets table,

ets:new(my_tree,[named_table, ordered_set, public]),
...

and then you can manage the link using the table key as "pointer"

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}}).

But may be you should look at more "erlang style" data representation to solve your problem. There is also an issue with the solution I propose, if there are multiple processes accessing to the tree, because the update of the tree is not atomic. In this case you should use mnesia, a data base layer above ets that will bring you atomic transaction.



来源:https://stackoverflow.com/questions/13896048/doubly-linked-data-structures-in-erlang

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!