1

I'm having trouble with my radix tree implementation. The idea is that I create the first node, then enter a number of binary numbers. The binary numbers determine whether a left node (0) or a right node (1) is created. Once I reach the end of the binary number, I set a node to "active".

Then I search through the tree to find an active node, and output the original binary numbers again by checking in which direction I had to go to reach the active node.

Here is the complete code:

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

typedef int bool;
enum { false, true };

typedef struct radixNode {
    bool active;
    struct radixNode * pnt;
    struct radixNode * l;
    struct radixNode * r;
} node;

void insert(node *root, char * B) {

    printf("String: %s\n", B);
    printf("1st: %c", B[0]);
    printf("\n\n", B);

    // digit is zero so we go left
    if (B[0] == '0') {

        printf("till here if");

        // left child doesn't exist, create it
        if (root->l == NULL) {

            root->l = malloc(sizeof(node));

            /* if the next index in the string does NOT contain a 1 or 0,
            the current index is the last index and the node is activated */
            if (B[1] == 1 || B[1] == 0)
                root->l->active = false;
            else
                root->l->active = true;

            root->l->pnt = root;
            root->l->l = NULL;
            root->l->r = NULL;
            insert(root->l,B++); // B++ removes the first digit of the string
        }

        // left child exists, traverse
        else {
            insert(root->l,B++);
        }
    }

    // digit is one, go right
    else if (B[0] == '1') {
        printf("first was 1\n");

        // right child doesn't exist, create it
        if (root->r == NULL) {

            printf("if triggered\n");

            root->r = malloc(sizeof(node));

            /* if the next index in the string does NOT contain a 1 or 0,
            the current index is the last index and the node is activated */
            if (B[1] == 1 || B[1] == 0)
                root->r->active = false;
            else
                root->r->active = true;

            root->r->pnt = root;
            root->r->l = NULL;
            root->r->r = NULL;
            insert(root->r,B++);
        }

        // left child exists, traverse
        else {
            printf("else triggered\n");
            insert(root->r,B++);
        }
    }
}

node * printTreeMin(node *root) {

    char C[10];

    /* goes left until it can't, appends 0 to string
    till it can't. if node is active, print the string */
    while (root->l != NULL) {

        C[strlen(C)] = '0';

        if (root->active == true)
            printf("%s\n",C);

        root = root->l;
    }

    return root;
}

// prints the next smallest binary number in the tree, returns the node it printed
node * printNextSmallest(node * root) {

    char C[10];

    // if right child exists, go there and find lowest node (after if same deal as printTreeMin() )
    if (root->r != NULL) {

        C[strlen(C)] = '1';
        if (root->active == true)
            printf("%s\n",C);

        root = root->r;

        while (root->l != NULL) {

            C[strlen(C)] = '0';
            if (root->active == true)
                printf("%s\n",C);

            root = root->l;
        }

        return root;
    }

    node * temp = root->pnt;

    while (temp != NULL && root == temp->r) {

        root = temp;
        temp = temp->pnt;
    }

    return temp;
}

void printRadixTree(node *root) {

    root = printTreeMin(root);

    while (printNextSmallest(root) != NULL)
        root = printNextSmallest(root);
}

void test() {

    node * tree = malloc(sizeof(node));
    tree->l = NULL;
    tree->r = NULL;

    // a)
    insert(tree,"101000");
    insert(tree,"10100");
    insert(tree,"10110");
    insert(tree,"101");
    insert(tree,"1111");

    // b)
    printRadixTree(tree);

}

int main() {
    test();
}

Here is the output:

if triggered
String: 101000
1st: 1

first was 1
if triggered
String: 101000
1st: 1

first was 1
if triggered
String: 101000
1st: 1

(and continuing ad infinitum)

Clearly I have an issue within the insert() function's recursion but considering I remove the first char of the binary number string when doing the recurrence, I don't understand how it can run infinitely.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
enenra
  • 111
  • 1
  • 11
  • What is this supposed to do: `C[strlen(C)] = '0';` – wildplasser Apr 27 '15 at 16:34
  • BTW: the recursive calls should probabbly be `insert(root->r, B+1);` instead of `insert(root->r, B++);` – wildplasser Apr 27 '15 at 16:40
  • @wildplasser it's supposed to add a 0 to the string which is empty before that. But I just realized as well that that can't be quite right. I think I mixed up some things there. – enenra Apr 27 '15 at 16:44
  • That was the issue! B+1 now doesn't have the infinite loop anymore. It still doesn't quite work yet but it's not looping indefinitely anymore. Thanks! Though I got to say I'm confused as to why this would be a problem. – enenra Apr 27 '15 at 16:46
  • See the difference between `B++` and `++B` in my answer – kdopen Apr 27 '15 at 16:52
  • And the funny thing is that the assignments to B[] in the insert() function will segfault, because it is called with a string literal as second argument: `insert(tree,"101000");` – wildplasser Apr 27 '15 at 16:56

1 Answers1

2

The reason for the infinite recursion is your choice of auto-increment operator. You want the prefix, not suffix form.

insert(..., B++)

increments the pointer (stripping the first character) after calling insert.

Instead the calls should be

insert (..., ++B)

You also have problems with your active flag, and this is your culprit

if (B[1] == 1 || B[1] == 0)

I think you meant

if (B[1] == '1' || B[1] == '0')

The first form is checking for a binary zero or one, rather than an ASCII character.

The result of this is that your active flag will probably be set incorrectly for most nodes. I expect that will then cause problems when traversing the tree. In fact, active will only be set to false when you are looking at the last '0' or '1' in the string (as B[1] at that point will be the terminating '\0').

Also, with recusive routines it is always a good idea to make the base case explicit, rather than implicit. Thus, one of the first blocks of code in insert should probably be

if (B[0] != '1' && B[0] != `0`)
    return;

then you can replace the else if with a simple else

if (B[0] == '0')
{
    // ... go left
}
else
{
    // ... go right
}
kdopen
  • 8,032
  • 7
  • 44
  • 52
  • Thanks! Looks like I missed those. I did realize that that would be a problem but apparently didn't change all of them. This hasn't fixed the infinite loop, however. It still appears unchanged (the output as well). – enenra Apr 27 '15 at 16:43
  • I added an edit for the infinite loop. There are enough problems in `insert` that they could be combining. You need to clean up the overall structure of the function so that you can be sure of the conditions which trigger a recursion. Such as "Why recurse at all if you set `active` to true?" – kdopen Apr 27 '15 at 16:47
  • Thanks! I actually had a brainfart there trying to think of a way to do `if (B[0] != '1' && B[0] != '0')` and couldn't figure it out. Will implement that. I have also made a number of other changes and gotten quite a bit farther now to the point where I think I have the `insert()` function working. I still need to get the search to work but that's for another topic. – enenra Apr 27 '15 at 17:15