您的位置:首页 > 其它

关于折半查找的细节思考

2016-10-24 16:12 267 查看
对于有序顺序表的查找我们知道最常用的是折半或者叫二分查找的策略。代码非常简洁,先看一眼:

int BinarySearch(vector<int> ins, int key)
{
int low = 0,high = ins.size() - 1, mid;
while(low <= high)
{
mid = (low + high) / 2;
if(ins[mid] == key)
{
return mid;
}
else if(ins[mid] > key)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}
return -1;
}


看着非常符合自然的思维过程,只是不知道会不会问一个问题:为什么high = mid - 1, low = mid + 1呢?是不是可以high = mid, low = mid呢?是不是更简洁?

答案是不可以的。

如果这么写了,将无法查找最后一个元素。当最后只剩3个元素时,mid可以取到中间那个数,这样low,high指向的数相邻。再次计算mid时,再也不能跳到high的值,因为我们知道计算机里的除有下取整的效果。所以,无法索引到最后一个数值。中间的都是可以的,而且第一个也可以。为什么呢?假设查找第一个数,最后low指向第一个,high指向第二个,下一次计算mid,恰好可以得到第一个数的位置。因此,可以查到。

看到这里,似乎可以想到,只需要low = mid + 1,则high两种方式都可以了,即high = mid,或者high = mid都行。

对的,确实是这样。分析的方法一样。关键在于看到low要有前进一步计算,这样才能达到最高位置的数。高位的就随便它好了。但是还是推荐high = mid - 1, low = mid + 1的写法。

完整测试代码,想实际验证的,编译运行测试即可。

#include <iostream>
#include <vector>
using namespace std;

int BinarySearch(vector<int> ins, int key)
{
int low = 0,high = ins.size() - 1, mid;
while(low <= high)
{
mid = (low + high) / 2;
if(ins[mid] == key)
{
return mid;
}
else if(ins[mid] > key)
{
high = mid - 1;
}
else
{
low = mid + 1;
}
}

return -1;
}

int main()
{
vector<int> ins;
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
int a;
cin >> a;
ins.push_back(a);
}
int key;
cin >> key;
cout << BinarySearch(ins,key) << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  折半查找