5

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.

yilmazhuseyin
  • 6,442
  • 4
  • 34
  • 38
  • Why not define your struct in a -define where child is defaulted to undefined. Then after you create node B create NodeA = B#node{children=A}.... Sorry that wot work. Wish I knew how to delete notes – Jr0 Dec 16 '12 at 05:39
  • why not try creating the children first and then assign them parents ? OR create parents and give them default children, then once the children are ready, update the parents ? – Muzaaya Joshua Dec 17 '12 at 08:15

5 Answers5

3

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"]

Community
  • 1
  • 1
yetihehe
  • 620
  • 8
  • 11
  • Is there a way to keep track/keep a reference to the end of a linked list to make append operations O(1) in erlang? – CMCDragonkai Oct 17 '14 at 13:00
  • No, you can't add to end of list. However you could simulate this with my example. Digraph uses ets, which has O(1) insertion cost. – yetihehe Dec 15 '14 at 15:16
3

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

danechkin
  • 1,306
  • 8
  • 15
3

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.

Pascal
  • 13,977
  • 2
  • 24
  • 32
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.

rvirding
  • 20,848
  • 2
  • 37
  • 56
2

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}.
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487