1

I have tried to traverse a multiway tree, but I'm trying to do in an efficient way but that doesn't really help me and more importantly I want to do it recursively.

My idea was like this: I have a tree, a child and it's siblings. I want to go recursively down with the childs and then as long as it has siblings to go recursively down on them too.

Here I will present to you my data structure and how I tried to implement this. Here is a full FUNCTIONAL "testable" that will ALSO create a photo for you to see the Tree and make use of the code:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define SIZE    100

typedef struct tree {
    int value;
    struct tree *child, *sibling;
} *Tree;

Tree initTree(int value) {
    Tree root = malloc(sizeof(struct tree));
    root->value = value;
    root->child = NULL;
    root->sibling = NULL;
    return root;
}

void drawTreeHelper(Tree tree, FILE* stream) {
    Tree tmp;
    if (tree == NULL) {
        return;
    }
    fprintf(stream, "    %ld[label=\"%d\", fillcolor=red]\n", (intptr_t) tree, tree->value);
    tmp = tree->child;

    while (tmp != NULL) {
        fprintf(stream, "    %ld -> %ld \n", (intptr_t) tree, (intptr_t) tmp);
        drawTreeHelper(tmp, stream);
        tmp = tmp->sibling;
    }
}

void drawTree(Tree tree, char *fileName) {
    FILE* stream = fopen("test.dot", "w");
    char buffer[SIZE];
    fprintf(stream, "digraph tree {\n");
    fprintf(stream, "    node [fontname=\"Arial\", shape=circle, style=filled, fillcolor=yellow];\n");
    if (tree == NULL)
        fprintf(stream, "\n");
    else if (!tree->child)
        fprintf(stream, "    %ld [label=\"%d\"];\n", (intptr_t) tree, tree->value);
    else
        drawTreeHelper(tree, stream);
    fprintf(stream, "}\n");
    fclose(stream);
    sprintf(buffer, "dot test.dot | neato -n -Tpng -o %s", fileName);
    system(buffer);
}

int main() {
    int i;
    char buffer[SIZE];
    Tree *forest = malloc(5 * sizeof(Tree));
    for (i = 0; i < 5; i++) {
        forest[i] = initTree(i);
    }

    forest[4]->child = forest[3];
    forest[4]->child->sibling = forest[2];
    forest[1]->child = forest[0];
    forest[1]->child->sibling = forest[4];

    for (i = 0; i < 5; i++) {
        sprintf(buffer, "tree_%d.png", i);
        if (forest[i]) {
            drawTree(forest[i], buffer);
        }
    }
    return 0;
}

The function that I want to create stays the same which is:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

    return findChild(root->child, value);
    Trie iter = root;
    while(iter)
    {
        return findChild(iter->sibling, value);
        iter = iter->sibling;
    }
}

I would expect to find the child but it returns me NULL if the node is not a direct child of root. Expectation of the function I want to create: Find the child in the most efficient way in the tree.

J. Homer
  • 147
  • 1
  • 11
  • Please provide a [mcve]. – Yunnosch Apr 11 '19 at 15:06
  • Is `sibling` the sibling of the tree, or of the `child`? I don't get how this structure is different from a "classical" tree. – Eugene Sh. Apr 11 '19 at 15:08
  • @EugeneSh. is the sibling of the tree, the current "looking-at" node, is not different from a "classical" tree, it's just a different notation. – J. Homer Apr 11 '19 at 15:19
  • @Yunnosch Why isn't this a minimal, complete and verifiable example? Also I would have added a photo with a tree, but I have too little reputation to do so. – J. Homer Apr 11 '19 at 15:19
  • It cannot be compiled and run. It does not demonstrate your problem. It lacks declarations. It is too small for all of that, but it is not minimal, because minimal imlies "just big enough". I doubt that you read the link I provided and thought "Yes, all of that is applicable to the code I have shown." – Yunnosch Apr 11 '19 at 15:24
  • Do not provide a photo of a tree. Provide a tree implementation, definition, initialisation, as part of a MCVE. – Yunnosch Apr 11 '19 at 15:26
  • @Yunnosch Look at the edit. I hope that's "good enough" for you. I really don't think you would have needed more than I posted lastly, but now you can easily "verify" it. – J. Homer Apr 11 '19 at 15:39
  • Do not try to please me. Try to ask your question so that it can easily be answered, without making the people who try to help you do the work you could have done instead. – Yunnosch Apr 11 '19 at 15:48
  • @Yunnosch Yeah, that's why I tried now to make it as simple as possible. – J. Homer Apr 11 '19 at 16:04

1 Answers1

0

This is your function:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

Here, you traverse down the child nodes, but you say return!

    return findChild(root->child, value);

So this code is never executed:

    Tree iter = root;
    while(iter)
    {
        return findChild(iter->sibling, value);
        iter = iter->sibling;
    }
}

Furthermore, the iteration is useless, since you traverse the next sibling anyway with a call to findChild. So the function should probably look like this:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

    Tree *ret = findChild(root->child, value);
    if (!ret)
        ret = findChild(root->sibling, value);

    return ret;
}

This should work as you expect.

Edit:

After an (unconditional) return, code is never executed. There is simply no codepath to "get around" that return.

This is probably the most efficient way (speaking in terms of runtime complexity) if the items in the tree do not follow a specific order. If the tree is ordered, you can exploit that by looking at the current item, comparing it with the searched for item and then - based on the comparison result - choose only one of the two paths child or sibling instead of traversing both.

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • Hello! Thank you for your answer, but why the code after is never executed? Isn't this how recursion works? Also, is this the most *efficient* way to do the search? – J. Homer Apr 11 '19 at 16:07
  • @A.Cretan I edited the answer to address your questions – Ctx Apr 11 '19 at 16:10
  • What do you mean "unconditional return"? Also the complexity would be O(N)? – J. Homer Apr 11 '19 at 16:17
  • @A.Cretan An unconditional return is a return, which is not inside a conditional block (i.e. not inside an if/else block). Yes, the runtime complexity would be O(n) (worst and average case) here with n being the number of elements in the tree. – Ctx Apr 11 '19 at 16:19