【问题标题】:Search Function in Binary Search Tree causes seg fault二叉搜索树中的搜索功能导致段错误
【发布时间】:2014-11-23 07:37:07
【问题描述】:

过去几天我一直试图让这个 BST 工作,但我在搜索功能上卡住了。逻辑似乎是正确的(除非我遗漏了非常重要的细节),但代码仍然存在问题。可能是因为我正在处理字符串吗?无论如何,这里有一些代码:

编辑:我已经指出了似乎出错的地方。事实证明,我的根始终为空。我放置了一个 printf 来测试 NULL 情况是否为真,并且它总是打印为真。我在这个问题的底部添加了我的树初始化。

(更新的)搜索功能:

//Thank you, M Oehm
node* search(node * tree, char *key)
{
    /* char *key is user input */
    int cmp;

    if(tree == NULL) {
        return NULL;
    }

    cmp = strcmp(key, tree->key);   
    if(cmp < 0) return search(tree->left, key);   
    if(cmp > 0) return search(tree->right, key);
    return tree;
}

main函数中的实现:

printf("Enter a string to search the tree with: ");
fgets(findNode, MAX_WORD, stdin);
findString = malloc(sizeof(char)*strlen(findNode)+1);
strcpy(findString,findNode);
printf("findString: %s\n", findString);
searched = search(&root, findString);
if(searched == NULL) {
    printf("No_such_key\n");
    free(findString);
    }
else {
    printNode(searched);
    free(findString);
    }
break;

树初始化(通过文件解析):

 /* Loop through each line in the file*/
 while(fgets(buffer, sizeof(buffer), file) != NULL) {
     tempToken = strtok(buffer, " \n");
     while(tempToken != NULL) {
         /* Assign default values */
         curr = (node *)malloc(sizeof(node));
         curr->left = curr->right = NULL;
         curr->key = malloc(sizeof(char)*strlen(tempToken)+1); /* +1 for '\0' */
         strcpy(curr->key, tempToken);
         curr->frequency = 1;           
         /* Insert node into tree */
         insert(&root, curr);
         /* Get next token */
         tempToken = strtok(NULL, " \n");
     }
 }
 /* Test insertion worked; close file */
 print_inorder(root);
 fclose(file);

插入函数:

void insert(node ** tree, node * item)
{
    /* If no root, item is root */
    if(!(*tree)) {
        *tree = item;
        return;
    }
    /* If item value is less than node in tree, assign to left */
    if(strcmp(item->key,(*tree)->key) < 0) {
        insert(&(*tree)->left, item);
    }
    else if(strcmp(item->key,(*tree)->key) > 0) {
        insert(&(*tree)->right, item);
    }
    else if(strcmp(item->key,(*tree)->key) == 0) {
        (*tree)->frequency++;
    }
}

打印功能显示插入工作正常。

【问题讨论】:

  • 您应该在开头测试if (*tree == NULL) 以捕获空子树的情况。你为什么要在这里使用双指针呢?您的函数不会修改树。
  • 我认为你应该确保树的构造是正确的——单元测试?
  • 我不是在搜索整棵树吗?或者我只需要使用一个节点:根。从那里我可以遍历到根的孩子等等?
  • 没错,搜索功能只需要获取Root节点和字符串值即可搜索。
  • 能否请您提供创建此 BST 的代码?你是如何创建那个“根”对象的?

标签: c string search segmentation-fault binary-search-tree


【解决方案1】:

您的代码中有两个错误:您没有检查将指针传递到的根节点是否为空,并且您没有从递归函数返回结果。

您的函数不会修改树,因此您不必将指针传递给节点。该方法对于修改树的函数很有用,例如用于插入或删除节点。你的函数应该传递一个指向根节点的指针。这也向用户表明树不会被修改。

所以这里有一个更正的版本:

node* search(node *tree, const char *key)
{
    int cmp;

    if (tree == NULL) return NULL;

    cmp = strcmp(key, tree->key);

    if (cmp < 0) return search(tree->left, key);
    if (cmp > 0) return search(tree->right, key);
    return tree;
}

该版本必须这样调用:

node *hit = search(tree, "bingo!");

请注意,此函数只进行一次字符串比较,并将结果保存在一个临时变量中。您的代码最多调用strcmp 3 次。

您不必在这里使用递归。这甚至有点浪费,因为您必须在第一次通话时将答案渗透。当每个步骤都必须维护一个状态时,递归很有用,您可以将其表示为局部变量。在这里,您只需更改输入 node

这是search 函数的非递归变体:

node* search(node *tree, const char *key)
{
    while (tree) {
        int cmp = strcmp(key, tree->key);

        if (cmp == 0) return tree;
        tree = (cmp < 0) ? tree->left : tree->right;
    }
    return NULL;
}

【讨论】:

  • 感谢您澄清传递指针的困惑。这更有意义。现在,我修复了我的搜索功能并且没有段错误,但我不断收到“No_such_key”,这是我返回的节点为 NULL 时的消息。 char *key 是用户输入;这可能是问题吗?我是否忘记添加空终止符或可能忘记删除此字符串中多余的不需要的字符?
  • 您在插入字符串的代码中删除了可能带有strtok 的尾随换行符,但您不会为搜索树的字符串执行此操作。
  • 啊,这是面部手掌时刻之一。现在可以了!非常感谢大家!
【解决方案2】:
search(&(*tree)->left, key);

应该是:

return search(&(*tree)->left, key);

对于正确的情况也是如此。

【讨论】:

    【解决方案3】:

    试着把你的函数改成这样。

    node* search(node * tree, char * key)
    {
        if(tree == NULL) {
            return NULL;
        }
    
        if(strcmp(key,tree->key) < 0) {
            return search(tree->left, key);
        }
    
        else if(strcmp(key,tree->key) > 0) {
            return search(tree->right, key);
        }
    
    
        printf("Success!\n");
        return tree;
    
    }
    

    一个简单的节点* 就足以解决您的问题。不需要双指针。

    【讨论】:

      猜你喜欢
      • 2022-11-15
      • 1970-01-01
      • 2019-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多