递归&返回布尔值

时间:2011-04-14 07:51:42

标签: c++ search recursion binary boolean

bool binsearch(string phrase, vector<string> words, int from, int to, int &test)
{
    while (tf == "y") //tf is a global variable
    {
        int mid = (to+from)/2;
        if (words[mid] == phrase) {tf = "t"; return true;}
        if (mid == test) {tf = "f"; return false;}
        if (words[mid] > phrase) {return binsearch(phrase, words, mid-1, to, mid);}
        else {return binsearch(phrase, words, from, mid+1, mid);}
     }
}

我正在努力让这个二进制搜索工作。我需要整体函数返回“true”或“false”。我理解递归是如何工作的,直到第6行或第7行执行并且调用return命令。我已经完成了研究,似乎没有办法在那里退出功能,它必须“放松”自己。 tf全局变量废话是这样的,当它解开时它不会再次执行那个身体......但我仍然没有得到我想要的结果。

本质上,我只想在调用return true或return false命令后退出函数ASAP,并相应地将值返回给main函数

由于

7 个答案:

答案 0 :(得分:4)

您可以使用STL的内置binary_search,如下所示:

binary_search(words.begin(),words.end(), phrase)

如果你这样做是为了学习;有一些事情......

  • 您不需要使用while循环。有三种情况需要考虑:单词出现在mid之前,midmid之后。这三种情况中的每一种return都是 - 因此甚至无法到达循环体的末端。
  • 完全时使用test,你需要这个变量吗?
  • 您应该仔细考虑完全仍需要搜索哪个索引范围。 fromto包含还是排他?您需要精确且一致。
  • 考虑正整数除法向下舍入。无论它们具有什么值,确保递归调用调用较小的范围 - 以避免无限循环。这有助于避免使用test变量(请参阅下面的David的评论)。
  • 使用全局变量不是好习惯;当然不是在其他纯粹的功能 - 我假设你这样做是为了调试目的?
  • tofrom有多大?在某些情况下,请注意to+from可能超过2^31-1
  • 在C ++中通常用迭代器表达这些概念。当然,你没必要。
  • 在C ++中通常尽可能通过const &传递大对象 - 这样,递归调用不需要复制整个向量。这对于正确性并不重要,但对于有效的代码来说实际上非常重要。

答案 1 :(得分:4)

我也不理解你的二进制搜索,除了递归之外使用全局变量会导致很难理解的程序。最好再次返回调用堆栈并正确“解开”它。请看以下示例(未经测试):

bool binsearch(const string& phrase, const vector<string> &words, int from, int to)
{
    if (from > to)
        return false; // word not found
    int mid = from + (to - from) / 2; // i think your calculation is wrong here
    int cmp = phrase.compare(words[mid]);
    if (cmp < 0)
        return binsearch(phrase, words, from, mid - 1);
    else if (cmp > 0)
        return binsearch(phrase, words, mid + 1, to);
    else
        return true; // word found
}

答案 2 :(得分:1)

vector<string> words函数中传递binsearch()作为参考。目前,无论何时调用函数,它都会不断创建vector<string>的副本。此外,如果你想更新那个矢量&lt;&gt;,那么通过引用传递是最好的方法。

return循环之外应该有while语句。那将是最后的'回归'。

答案 3 :(得分:1)

摆脱这种情况的经典方法之一:在没有递归的情况下重写它。

例如,使用while循环,然后在找到结果后立即使用中断。您可以查看以下代码(未编译,只需从您自己的代码中快速编写)

bool binsearch(const string& phrase, const vector<string> &words, int from, int to)
{
    bool retVal = false;
    int start = from;
    int end = to;


    while(start<end) {
       int mid = from + (to - from) / 2; // i think your calculation is wrong here
       int cmp = phrase.compare(words[mid]);
       if (cmp < 0) {
           end=mid-1;
       } else if (cmp > 0) {
           start=mid+1;
       } else {
           retVal = true;
           break;
       }
    }
    return retVal;
}

没有优雅或可移植的方式来跳出一个完整的调用堆栈,它充其量是相当冒险的。此外,去失函数将更快:它不需要在堆栈上推送东西并进行函数调用

修改

  • 添加了缺失的回复
  • 关于表演:只是基准测试。在这种特殊情况下,代码复杂性(对于人类读者来说)几乎是相同的,但是根据算法,它可能要复杂得多(甚至不可能)。

答案 4 :(得分:1)

您的代码有几个问题。对于初学者, 我不清楚tofrom是什么意思:它们是包容性的,还是 独家。如果他们都包容(你的论点 到递归调用似乎建议),你如何检测到 结束。 test是什么意思?你好像用它作为一个 当你没有找到这个词的时候结束标准,但是我不知道怎么做。

如果我写这篇文章,我会使用一个简单的帮助类来保存 目标和单词列表(但你可以传播它们 明确地),以及一个包装函数,以便客户端代码 不必指定tofrom参数。有 不需要全局变量或任何其他test。和 我会使用C ++中惯用的半开区间:更低 绑定包含,上限独占(所以top == bottom 指定一个空范围,所以我没有找到 元素):

bool 
binSearch( std::string const& target,
           std::vector<std::string> const& words );

namespace {

    class BinSearcher
    {
        std::vector<std::string> const& myWords;
        std::string const& myTarget;

        bool doSearch( int bottom, int top ) const
        {
            int mid = (top - bottom) / 2;
            return mid != top
                && (myTarget == myWords[mid]
                    || (myTarget > myWords[mid] && doSearch( mid + 1, top ))
                    || (myTarget < myWords[mid] && doSearch( bottom, mid ));
        }
        BinSearcher( std::string const& target,
                     std::vector<std::string> const& words )
            : myWords( words )
            , myTarget( target )
        {
        }
        friend bool binSearch( std::string const&,
                               std::vector<std::string> const& );
    };
}

bool 
binSearch( std::string const& target,
           std::vector<std::string> const& words )
{
    BinSearcher searcher( target, words );
    return searcher.doSearch( 0, words.size() );
}

请注意,在测试之前无法进行比较 范围不相等;如果全部,它将导致越界访问 元素的数量少于目标。

另外:我认为你是出于教学原因这样做的。 否则,您应该只使用标准中的功能 图书馆。我通常不会在这里使用递归:有 一个简单的迭代解决方案:

namespace {

    bool
    doBinSearch( std::string const& target,
                 std::vector<std::string> const& words,
                 int bottom,
                 int top )
    {
        bool found = false;
        while ( bottom != top && ! found ) {
            int mid = (top - bottom) / 2;
            int cmp = target.compare( words[mid] );
            if ( cmp < 0 ) {
                top = mid ;
            } else if ( 0 < cmp ) {
                bottom = mid + 1;
            } else {
                found = true;
            }
        }
        return found;
    }
}

bool
binSearch( std::string const& target,
           std::vector<std::string> const& words )
{
    return doBinSearch( target, words, 0, words.size() );
}

(最后,您会注意到我已将您的参数转换为 引用。它没有改变逻辑中的任何东西 代码,但如果words相对较大,那么它就会变得很好 对绩效产生重大影响。)

答案 5 :(得分:0)

您可以使用longjmp,也称为“非本地goto”来立即退出内部递归,但问题是这种微优化是否值得给它带来麻烦。

更好的选择是将递归更改为循环。由于所有递归调用都处于“尾部位置”(是return的参数),因此可以使用重置参数变量的代码替换它们。不幸的是,我不明白你的代码,所以我不能给你一个例子。

答案 6 :(得分:0)

这是使用递归的经典练习 - 当然,人们也可以非递归地做事,但是“让递归管理一个人的簿记”非常优雅。对于那些膝跳反应是“反复进行”的人,我建议对合并排序或快速排序进行类似的练习。非常相似的递归结构,但在递归上下文中的簿记有很大的缓和。在现代CPU上的递归代码 - 惊喜! - 通常以快速或更快的速度运行,以便启动。

这是我的递归实现,使用OP的问题上下文。注意,不需要单独测试中点元素:在C ++“小于”范例的上下文中,对于比较谓词(给定&lt;,可以通过.not。(a.lt.b)推断相等性。)。 .not。(b.lt.a)),对中点相等的额外测试没有多大意义,尽管在具有多值比较结果的字符串类的特殊情况下,它可能会产生适度的加速以增加特殊性处理0返回结果。我的示例版本仅假设&lt; (从某种意义上说,如果一个人真的只有&lt ;,那么就会稍微重新安排分而治之的条件来使用它),这更容易概括为数字和用户定义的数据类型:

bool binsearch(const string&phrase, vector<string>&words, int from, int to)
{
    if(from > to) return false;    // range sanity check
    if(from == to) return (phrase.compare(words[to]) == 0);    // bottom of the recursion
    int mid = from + (to-from)/2;        // Range still has >= 2 elements; set up to recurse
    if(phrase.compare(words[mid]) <= 0)  // Recurse into the subinterval bracketing the target
        return binsearch(phrase,words, from,mid);
    else
        return binsearch(phrase,words, mid+1,to);
}

这是上面的非递归版本,它纠正了用户'Bruce'发布的示例代码的几个问题,并且再次使用了单独的中点值测试:

bool binsearch_nr(const string& phrase, const vector<string> &words, int from, int to)
{
    if(from > to) return false;    // range sanity check
    while(from < to) {
        int mid = from + (to-from)/2;
        int cmp = phrase.compare(words[mid]);
        if (cmp <= 0)
            to = mid;
        else
            from = mid+1;
    }
    return (phrase.compare(words[to]) == 0);
}

我使用100万个准随机文本片段的矢量进行了上述2个实现的比较时序,在MacOS上使用gcc 4.2构建的代码...递归版本运行速度慢约20%。但是,对于我的手动合并排序代码,递归更快。 YMMV。