• 你真的会二分查找吗?


    二分查找简介

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

    时间复杂度为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
    ", p1 - st);       // 1
    
    	It p2 = upper_bound(st, ed, 2);//>2的第一个位置
    	printf("%d
    ", p2 - st);       // 4
    
    	pair<It, It> p = equal_range(st, ed, 2);        //==2的位置
    	printf("%d-%d
    ", p.first - st, p.second - st); // 1-4
    
    	bool exist = binary_search(st, ed, 2); //2是否存在
    	printf("%d
    ", 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


    Keep it simple!
    作者:N3verL4nd
    知识共享,欢迎转载。
  • 相关阅读:
    学而时习之,不亦乐乎。
    uva10025 The ? 1 ? 2 ? ... ? n = k problem
    uva591 Box of Bricks
    uva253 Cube painting
    uva10194 Football (aka Soccer)
    用WORD2007发布博客文章
    Microsoft Silverlight 1.0 SDK 中文版推出
    vista sp1/office 2007 sp1和xp sp3都出来了
    scrollLeft,scrollWidth,clientWidth,offsetWidth,screen.width全解析(转帖)
    在C#中使用My命名空间
  • 原文地址:https://www.cnblogs.com/lgh1992314/p/6616322.html
Copyright © 2020-2023  润新知