关于折半查找的细节思考

来源:互联网 发布:淘宝联盟无法登录 编辑:程序博客网 时间:2024/06/15 03:11

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

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;}
0 0
原创粉丝点击