ctreetree-traversalmultiway-tree

How to tree traversal a multiway tree


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.


Solution

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