【问题标题】:Binary search tree lookup output二叉搜索树查找输出
【发布时间】:2021-01-01 04:53:06
【问题描述】:

我正在尝试为二叉搜索树实现查找功能。如果我查找树的根,它确实返回 true,但当我查找树中的其他条目时,它返回 false。当我调试它时,该函数似乎返回 1,但随后会继续运行,最后返回 0。我的理解是该函数应在返回任何值后立即终止,因此我不确定为什么会发生这种情况。

int lookup(int n,struct node* x)
{
    if (x->data==n)
    {
        return 1;
    }
    else if (x->left==NULL && x->right==NULL)
    {
        return 0;
    }
    else if (n>x->data && x->right!=NULL)
    {
        lookup(n,x->right);
    }
    else
    {
        lookup(n,x->left);
    }
    return 0;
}

【问题讨论】:

  • 当你进行递归调用时,你会返回什么?
  • 您可能想写return (lookup(n,x->right)); 而不仅仅是lookup(n,x->right);
  • 对不起,@Stef。我在打字时没有看到你的评论。事实证明是一样的,但是我实际上并没有复制您的输入……请随意做出您自己的解释性答案,我们可以进行投票。 ;-)
  • 我想我现在明白了。所以“return 1”退出了查找的递归调用,但由于我没有返回它,第一个调用仍然达到“return 0”?两者都非常有帮助,谢谢。
  • sb2346 在您决定接受哪一个之前,请稍等一下 Stefs 可能即将给出的答案。他值得一点耐心。

标签: c recursion struct binary-search-tree function-definition


【解决方案1】:

你做了一个递归调用,但你不返回它的结果!

您的代码最简单的递归版本是:

int lookup(int n, struct node* x)
{
    if (x == NULL)
        return 0;

    if (n == x->data)
        return 1;

    if (n < x->data)
        return lookup(n, x->left);
    else
        return lookup(n, x->right);
}

只要它没有离开分支,它就会测试当前节点 - 当找到值时,返回 1,否则查找潜入左或右分支。当路径结束时 (x == NULL) 未找到值,返回 0。

结果在递归返回时向上传播。

最简单的迭代版本:

int lookup(int n, struct node* x)
{
    while (x != NULL)
    {
        if (n == x->data)
            return 1;

        if (n < x->data)
            x = x->left;
        else
            x = x->right;
    }

    return 0;
}

它的工作方式与递归类似,只是它不深入递归,只是将x 指针向下移动。如果在分支结束之前找到该值,则返回 1。否则扫描经过一片树叶时结果为 0。

【讨论】:

    【解决方案2】:

    该函数的行为不正确,因为它在这些 if 语句中不返回任何内容

        else if (n>x->data && x->right!=NULL)
        {
            lookup(n,x->right);
        }
        else
        {
            lookup(n,x->left);
        }
    

    即控制将传递到if-else语句之后的最后一个return语句

        return 0;
    

    但是如果你会像这样更新函数

    int lookup(int n,struct node* x)
    {
        if (x->data==n)
        {
            return 1;
        }
        else if (x->left==NULL && x->right==NULL)
        {
            return 0;
        }
        else if (n>x->data && x->right!=NULL)
        {
            return lookup(n,x->right);
        }
        else
        {
            return lookup(n,x->left);
        }
        return 0;
    }
    

    尽管如此,该函数可以调用未定义的行为,因为它不检查指针 x 是否等于 NULL

    例如,假设x-&gt;data 不等于n 并且n 小于x-&gt;data。还假设x-&gt;left 等于NULLx-&gt;right 不等于NULL

    在这种情况下,第一个 if 语句的子语句

        if (x->data==n)
        {
            return 1;
        }
    

    不会被执行。

    第二个if语句的子语句也不会被执行,因为x-&gt;right不等于NULL

        else if (x->left==NULL && x->right==NULL)
        {
            return 0;
        }
    

    第三个 if 语句也会存在同样的问题。

    所以控件将在最后一个 else 语句中传递

        else
        {
            lookup(n,x->left);
        }
    

    使用空指针x-&gt;left 调用函数的位置。因此,在函数的第二次调用中,您将尝试使用空指针来访问内存

        if (x->data==n)
        {
            return 1;
        }
    

    函数可以写成如下方式。请注意,由于函数不会更改树本身,因此它的第二个参数应使用限定符 const 声明。

    int lookup( int n, const struct node *x )
    {
        if ( x == NULL )
        {
            return 0;
        }
        else if ( n < x->data )
        {
            return( n, x->left );
        }
        else if ( x->data < n )
        {
            return ( n, x->right );
        }
        else
        {
            return 1;
        }
    }
    

    同样,通常这样的函数使用第一个参数来声明,该参数指定指向节点(指向树)的指针,第二个参数指定搜索的内容。就像

    int lookup( const struct node *x, int n );
    

    甚至喜欢

    _Bool lookup( const struct node *x, int n );
    

    【讨论】:

      【解决方案3】:

      您的递归lookup 调用(即lookup(n,x-&gt;right);lookup(n,x-&gt;left);)返回的值被忽略,即使它是正确的。
      这是因为在函数结束时(即从其中一个调用返回后)你无条件地return 0;

      lookup(n,x-&gt;XXX); 替换为return lookup(n,x-&gt;XXX); 是您想要做的。

      【讨论】:

      • 如果 Stef 在这里也有解释的答案,请投票赞成。
      • 我已经这样做了——而且我喜欢你的方式。如果它仍然需要它,请随意。虽然我更喜欢你的建议作为评论。
      猜你喜欢
      • 1970-01-01
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 2011-02-05
      • 2021-10-20
      • 1970-01-01
      相关资源
      最近更新 更多