[英]recursion & returning boolean values
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函数
谢谢
您可以使用STL的内置binary_search ,如下所示:
binary_search(words.begin(),words.end(), phrase)
如果你这样做是为了学习; 有几件事......
mid
, mid
或mid
之后。 这三种情况中的每一种都return
s - 因此甚至无法到达循环体的末端。 test
,你需要这个变量吗? from
和to
包括或不? 你需要精确和一致。 test
变量(请参阅下面的David的评论)。 to
和from
呢? 在某些情况下,请注意, to+from
可能会超过2^31-1
。 const &
传递大对象 - 这样,递归调用不需要复制整个向量。 这对于正确性并不重要,但对于高效代码而言实际上非常重要。 我也不理解你的二进制搜索,除了递归之外使用全局变量会导致很难理解的程序。 最好再次返回调用堆栈并正确“解开”它。 请看以下示例(未经测试):
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
}
在binsearch()
函数binsearch()
vector<string> words
作为参考binsearch()
。 目前,每当调用不需要的函数时,它都会不断创建vector<string>
副本。 此外,如果你想要更新那个矢量<>,那么通过引用传递是最好的方法。
在while
循环之外应该有return
语句。 那将是最后的'回归'。
摆脱这种情况的经典方法之一:在没有递归的情况下重写它。
例如,使用while循环,然后在找到结果后立即使用break。 您可以查看以下代码(未编译,只需从您自己的代码中快速编写)
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;
}
没有优雅或便携的方式来跳出一个完整的调用堆栈,它充其量是相当冒险的。 此外,去失效函数将更快:它不需要在堆栈上推送东西并进行函数调用
编辑
你的代码有几个问题。 对于初学者来说,目前还不清楚是什么to
和from
平均值:他们是包罗万象,或独占。 如果它们都是包容性的(你的递归调用的参数似乎表明了这一点),你如何检测结束。 test
意味着什么? 当你找不到这个词的时候,你似乎正在使用它作为最终标准,但我不知道如何。
如果我写这个,我会使用一个简单的辅助类来保存目标和单词列表(但你可以传播下来明确),和一个包装函数,以便客户端代码没有指定to
from
论点。 不需要全局变量或任何其他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
相对较大,则会对性能产生非常大的影响。)
这是使用递归的经典练习 - 当然,也可以非递归地执行操作,但是“让递归管理一个人的簿记”非常优雅。 对于那些膝跳反应是“反复进行”的人,我建议对合并排序或快速排序进行类似的练习。 非常相似的递归结构,但在递归上下文中的簿记有很大的缓和。 在现代CPU上的递归代码 - 惊喜! - 通常以快速或更快的速度运行,以启动。
这是我的递归实现,使用OP的问题上下文。 注意,不需要单独测试中点元素:在C ++“小于”范式的上下文中,对于比较谓词(给定<,可以通过.not。(a.lt.b)来推断相等性。)。不。(b.lt.a)),对中点相等的额外测试没有多大意义,尽管在字符串类的特殊情况下具有多值比较结果,它可能会产生适度的加速以增加特殊处理为0返回结果。 我的示例版本仅假设<(从某种意义上说,如果一个人真的只有<,一个人会稍微重新排列使用它的分而治之条件),这更容易概括为数字和用户定义的数据类型:
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%。 但是,对于我的手动合并排序代码,递归更快。 因人而异。
您可以使用longjmp
(也称为“非本地goto
”)立即退出内部递归,但问题是这种微优化是否值得麻烦。
更好的选择是将递归更改为循环。 由于所有递归调用都处于“尾部位置”(是return
的参数),因此可以使用重置参数变量的代码替换它们。 不幸的是,我不明白你的代码,所以我不能给你一个例子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.