0

I am using the tree.hh implementation. I have a simple "tree" like the following (A, B and C are siblings without parents, B1 is child to B):

A
B
  B1
C

Now I want to "move" C to be also a child of B. I tried the following minimal example, but did not find a easy way to do this using the methods in tree.hh.

The only solution I found was:

  1. Extract a subtree from C and its children (which removes it from the original tree)
  2. Append the subtree of C as child to the desired new parent B

See code on pastebin.com

#include <iostream>
#include "tree.hh"
#include "tree_util.hh"

void print_tree(const tree<std::string>& tr)
{
    tree<std::string>::pre_order_iterator it = tr.begin();
    tree<std::string>::pre_order_iterator end = tr.end();
    if(!tr.is_valid(it)) return;
    int rootdepth=tr.depth(it);
    std::cout << "-----" << std::endl;
    while(it!=end) {
        for(int i=0; i<tr.depth(it)-rootdepth; ++i)
            std::cout << "  ";
        std::cout << (*it) << std::endl << std::flush;
        ++it;
        }
    std::cout << "-----" << std::endl;
}

int main(int, char **)
{
    tree<std::string> my_tree;

    tree<std::string>::iterator iA = my_tree.insert(my_tree.end(), "A");
    tree<std::string>::iterator iB = my_tree.insert(my_tree.end(), "B");
    tree<std::string>::iterator iB1 = my_tree.append_child(iB, "B1");
    tree<std::string>::iterator iC = my_tree.insert(my_tree.end(), "C");        
    print_tree(my_tree);

    // this makes a copy of "C" --> not what I want
    auto iC_append = my_tree.append_child(iB, iC);
    print_tree(my_tree);
    my_tree.erase(iC_append);

    // this extracts "C" into a separate tree and then appends the tree as child to "B"
    tree<std::string> sub_tree = my_tree.move_out(iC);
    my_tree.move_in_as_nth_child(iB, my_tree.number_of_children(iB), sub_tree);
    print_tree(my_tree);
}

I doubt, that this is the most simple solution possible. Any ideas what I am doing wrong?

Thanks!

Cheers, Jonathan

EliteTUM
  • 705
  • 2
  • 8
  • 21
  • BTW, I forgot: Yes I did take a look at [this question](https://stackoverflow.com/questions/10801020/how-to-reparent-using-tree-hh), but could not figure out how to solve this using ::move_after. – EliteTUM Jan 02 '18 at 16:51
  • You lose my help because firewalls are preventing me from accessing your code via link. Perhaps pasting the minimal amount of code will help other people. – Thomas Matthews Jan 02 '18 at 18:05
  • @ThomasMatthews: Thanks for the hint. I copied the wrong link. Using the proper language hint for cpp I also was able to insert the example code - which did not work before. Any help is highly appreciated. I managed to fix most of my problems so far. Unfortunately, I have to perform the above step (change parent) multiple times. At some point, this leads to inconsistencies, seems like my graph results in having cycles. – EliteTUM Jan 02 '18 at 22:25
  • I couldn't edit my previous comment, so I add another: I just tried building the above example in Windows using Visual Studio 2015 (x64) instead of gcc in Linux. It breaks when calling ::move_in_as_nth_child(), so I guess I really really am doing this the wrong way and obviously have not understood the tree.hh-concept :( – EliteTUM Jan 02 '18 at 22:57

2 Answers2

1

Use move_after, as in

my_tree.move_after(iB1, iC);

This moves the node at iC (and any children, if present) to become a sibling of B.

Kasper Peeters
  • 1,580
  • 2
  • 18
  • 37
0

It took some time but I think I found an - at least feasible and more or less robust - answer.

I first append an empty child node to the desired new parent. Then I use ::move_ontop() to make my desired child node (plus its children) the replacement for the empty child node from the previous step.

So my example from above now looks like this (to test whether all chilren are correctly being moved as well, I introduced an additional child node C1 as child to C):

#include <iostream>
#include <string>
#include "tree.hh"
#include "tree_util.hh"

void print_tree(const tree<std::string>& tr)
{
    tree<std::string>::pre_order_iterator it = tr.begin();
    tree<std::string>::pre_order_iterator end = tr.end();
    if (!tr.is_valid(it)) return;
    int rootdepth = tr.depth(it);
    std::cout << "-----" << std::endl;
    while (it != end) {
        for (int i = 0; i<tr.depth(it) - rootdepth; ++i)
            std::cout << "  ";
        std::cout << (*it) << std::endl << std::flush;
        ++it;
    }
    std::cout << "-----" << std::endl;
}

int main(int, char **)
{
    tree<std::string> my_tree;

    tree<std::string>::iterator iA = my_tree.insert(my_tree.end(), "A");
    tree<std::string>::iterator iB = my_tree.insert(my_tree.end(), "B");
    tree<std::string>::iterator iB1 = my_tree.append_child(iB, "B1");
    tree<std::string>::iterator iC = my_tree.insert(my_tree.end(), "C");
    tree<std::string>::iterator iC1 = my_tree.append_child(iC, "C1");
    print_tree(my_tree);

    // First append an empty-child to the desired parent...
    auto iNew = my_tree.append_child(iB);
    // ...and then "squash" the empty child with the source child (and sub-children)
    iC = my_tree.move_ontop(iNew, iC);
    print_tree(my_tree);
}

The output now is, as desired:

-----
A
B
  B1
C
  C1
-----
-----
A
B
  B1
  C
    C1
-----
EliteTUM
  • 705
  • 2
  • 8
  • 21