你真的会二分查找吗?

来源:互联网 发布:开过淘宝店铺能注销吗 编辑:程序博客网 时间:2024/05/18 03:32

二分查找简介

二分查找是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。

时间复杂度为O(log n)

例如对于{1,3,4,6,7,8,10,13,14}构成的有序序列对应的查找树:



算法实现

最简单的二分查找算法:

即找到返回下标,找不到返回-1,(坐标范围:[0~nums.size() - 1])

#include <iostream>#include <vector>#include <set>#include <algorithm>#include <string>#include <sstream>#include <cstring>#include <cmath>using namespace std;int BinarySearch(vector<int>& nums, int target){int left = 0;int right = nums.size() - 1;    while(left <= right)    {        int mid = left + ((right - left) >> 1);        if (nums[mid] > target)        {            right = mid - 1;        }        else if(nums[mid] < target)        {            left = mid + 1;        }        else        {        return mid;        }    }    return -1;}int main(){vector<int>vec{1,3,5,5,5,7,8};cout << BinarySearch(vec, 3);return 0;}

二分查找的变种

查找第一个与target相等的元素位置,找不到返回-1

int BinarySearchLeft(vector<int>& nums, int target)    {        int left = 0;        int right = nums.size() - 1;        while(left <= right)        {            int mid = left + ((right - left) >> 1);                      if (nums[mid] >= target)            {                right = mid - 1;            }            else            {                left = mid + 1;            }        }        if (left <= (int)nums.size() - 1 && nums[left] == target)        {            return left;        }        return -1;    }

查找最后一个与target相等的元素位置,找不到返回-1


int BinarySearchRight(vector<int>& nums, int target)    {        int left = 0;        int right = nums.size() - 1;        while(left <= right)        {            int mid = left + ((right - left) >> 1);                      if (nums[mid] > target)            {                right = mid - 1;            }            else            {                left = mid + 1;            }        }        if (right >= 0 && nums[right] == target)        {            return right;        }        return -1;    }

查找最后一个小于key的元素

#include <iostream>#include <vector>#include <set>#include <algorithm>#include <string>#include <sstream>#include <cstring>#include <cmath>using namespace std;int BinarySearch(vector<int>& nums, int target){int left = 0;int right = nums.size() - 1;    while(left <= right)    {        int mid = left + ((right - left) >> 1);        if (nums[mid] >= target)        {            right = mid - 1;        }        else if(nums[mid] < target)        {            left = mid + 1;        }    }    return right;}int main(){vector<int>vec{1,3,5,5,5,7,8};cout << BinarySearch(vec, 7);return 0;}

查找第一个大于key的元素

#include <iostream>#include <vector>#include <set>#include <algorithm>#include <string>#include <sstream>#include <cstring>#include <cmath>using namespace std;int BinarySearch(vector<int>& nums, int target){int left = 0;int right = nums.size() - 1;    while(left <= right)    {        int mid = left + ((right - left) >> 1);        if (target >= nums[mid])        {            left = mid + 1;        }        else if(target < nums[mid])        {            right = mid - 1;        }    }    return left;}int main(){vector<int>vec{1,3,5,5,5,7,8};cout << BinarySearch(vec, 5);return 0;}
如果返回nums.size()则说明不存在。

查找第一个等于或者小于key的元素

#include <iostream>#include <vector>#include <set>#include <algorithm>#include <string>#include <sstream>#include <cstring>#include <cmath>using namespace std;int BinarySearch(vector<int>& nums, int target){    int left = 0;    int right = nums.size() - 1;    while(left <= right)    {        int mid = left + ((right - left) >> 1);        if (target <= nums[mid])        {            right = mid - 1;        }        else        {            left = mid + 1;        }    }    if (nums[left] != target)    {        return left - 1;    }    return left;}int main(){    vector<int>vec{1,3,5,5,5,7,8};    cout << BinarySearch(vec, 5);    return 0;}

查找最后一个等于或者大于key的元素

#include <iostream>#include <vector>#include <set>#include <algorithm>#include <string>#include <sstream>#include <cstring>#include <cmath>using namespace std;int BinarySearch(vector<int>& nums, int target){    int left = 0;    int right = nums.size() - 1;    while(left <= right)    {        int mid = left + ((right - left) >> 1);        if (target >= nums[mid])        {            left = mid + 1;        }        else        {            right = mid - 1;        }    }    if (nums[right] != target)    {        return right + 1;    }    return right;}int main(){    vector<int>vec{1,3,5,5,5,7,8};    cout << BinarySearch(vec, 5);    return 0;}


STL中的二分查找

STL中与二分查找相关的函数有4个,分别是lower_bound, upper_bound, equal_range和binary_search,下面通过一个简单的例子说明各个函数的使用方法。
#include <cstdio>#include <algorithm>#include <vector>using namespace std;int main(){int a[6] = {1, 2, 2, 2, 3, 4}; //已排序vector<int> v(a, a + 6);typedef vector<int>::iterator It; //迭代器类型It st = v.begin(), ed = v.end();  //起始迭代器It p1 = lower_bound(st, ed, 2);//>=2的第一个位置printf("%d\n", p1 - st);       // 1It p2 = upper_bound(st, ed, 2);//>2的第一个位置printf("%d\n", p2 - st);       // 4pair<It, It> p = equal_range(st, ed, 2);        //==2的位置printf("%d-%d\n", p.first - st, p.second - st); // 1-4bool exist = binary_search(st, ed, 2); //2是否存在printf("%d\n", exist);                 //1 (是)}
其中每个函数实现的功能如下:
binary_search:查找某个元素是否出现。
lower_bound:查找第一个大于或等于某个元素的位置。
upper_bound:查找第一个大于某个元素的位置。
equal_range:查找某个元素出现的起止位置。注意,终止位置为最后一次出现的位置加一。
其中lower_bound和upper_bound的功能可能比较别扭,可以这样看:对于已排序的数组1 2 2 2 3 4,元素2出现了3次,第一次出现的位置为1,最后一次的位置为3,lower_bound即为这个第一次出现的位置,而upper_bound本意是要标志最后一次出现的位置,但STL中习惯使用左闭右开的区间,于是upper_bound返回的结果应该为最后一次出现的位置的下一个位置。当查找的元素一次都未出现时,二者返回的结果都是第一个大于该元素的位置。

参考:http://www.cnblogs.com/ider/archive/2012/04/01/binary_search.html


0 0
原创粉丝点击