基数树实现中的无限循环问题

时间:2015-04-27 16:16:04

标签: c string binary-tree infinite-loop radix-tree

我的基数树实现遇到了问题。我的想法是创建第一个节点,然后输入一些二进制数。二进制数确定是创建左节点(0)还是右节点(1)。一旦我到达二进制数的末尾,我将节点设置为“活动”。

然后我在树中搜索以查找活动节点,并通过检查我必须到达活动节点的方向再次输出原始二进制数。

以下是完整的代码:

#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();
}

这是输出:

if triggered
String: 101000
1st: 1

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

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

(并且无限期地继续)

显然我在insert()函数的递归中有一个问题,但考虑到我在重复时删除二进制数字符串的第一个字符,我不明白它是如何无限运行的。

1 个答案:

答案 0 :(得分:2)

无限递归的原因是您选择自动增量运算符。你想要前缀,而不是后缀形式。

insert(..., B++)

在调用insert。

之后递增指针(剥离第一个字符)

相反,调用应该是

insert (..., ++B)

您的active标志也存在问题,这是您的罪魁祸首

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

我认为你的意思是

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

第一种形式是检查二进制零或一,而不是ASCII字符。

结果是大多数节点的active标志可能设置不正确。我希望在遍历树时会出现问题。事实上,active只会在您查看字符串中的最后一个false'0'时设置为'1'(此时B[1]将为是终止'\0')。

此外,对于重复使用的例程,使基本案例显式而非隐式是一个好主意。因此,insert中的第一个代码块之一应该是

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

然后您可以使用简单的else if

替换else
if (B[0] == '0')
{
    // ... go left
}
else
{
    // ... go right
}