二分查找--整理

二分查找,无论是从名字还是理论都十分简单一个算法,其博大精深,简直恐怖。Jon Bentley:90%以上的程序员无法正确无误的写出二分查找代码。

  别人不知道,反正我早上是写了好久,这个查找算法,将查找的复杂度从 o( n ) 降到了 o( logn ) ,当之无愧的的好算法,更是许多高级算法的优化策略之一。

  

  二分查找之基本思路

  虽然二分查找是一个很吊的算法,但是跟很多算法一样,需要使用的基础条件——序列有序!

  先假设一个单调非增序列:1 2 3 4 5 6 ,求找到3的位置,地球人都会马上这么想——一个一个找咯,可是这样很慢!

  于是有人想要加快查找速度,他们发现如果从中间开始找,那么每次比较后就至少可以排除一半的数,这就是二分查找的基本思想——折半。

  1)设置三个指针变量(应该说是指针性质的变量,索引也是可以的)——low
,mid 和 high,并且满足 mid = ( low + high ) / 2;

  2)设置循环,进行target值与mid存储值的比较,根据比较结果更新low或者high;

  3)在
2)中,若出现找到target的情况,则返回mid指针;如果一直找不到,则返回空指针。

  下面是代码:

  

//方法一int binary_search(int n, int v)
{
    int low=0,high=n-1,mid;
    while (low<=high)
    {
        mid=(low+high)/2;
        if (a[mid]==v)
            return mid;
        if (a[mid]<v)
            low=mid+1;
        if (a[mid]>v)
            high=mid-1;
    }
    return -1;
}

  看起来好像没什么问题,实际上在一些情况下 ,答案会很奇怪:1 2 2 4 5,我们如果找2,答案 -> 2 (这是索引啊!)  

  那么问题来了,为什么是返回第二个,而不是第一个呢?其实很简单,当序列出现重复元素时,我们找到了当然是其中“任意”一个啦!

  但是其实往往我们需要处理的序列总是拥有重复元素的,所以,我们需要优化!

  我们先来分析原来的二分查找 —— left < mid <right ,即我们将“=”的情况全部交给mid处理,于是mid会给你各种答案:

  所以,我们不妨按这种规则来二分 —— left <= mid < right !

  我们可以看看代码:

//方法二:返回第一个位置int lowerBound(const int a[],const int size,const int target)
{
    int low=0,high=size-1,mid;
    while(low<high)
    {
        mid=(low+high)/2;
        if(a[mid]<target)
            low=mid+1;
        else high=mid;
    }
    if(a[low]==target) return low;
    else return -1;
}   

  这里我们会发现两种查找方式一个最明显的不同:方法一是找到答案立即返回,方法二则是一直找到最底部(当成树看)然后再返回!感觉方法二要一

  直找到底部好像会很慢,但是事实证明:方法一才是最慢的,所以我们以后可以抛弃第一种写法啦!

  当然,方法二是返回第一个位置,那么就会有返回最后一个位置的算法啦!

  上代码:

//方法三:返回最后一个位置int upperBound(const int a[], const int size, const int target)
{
    int low=0,high=size-1,mid;
    while(low<high)
    {
        mid=(low+high)/2+1;
        if(a[mid]>target)
            high=mid-1;
        else low=mid;
    }
    if(a[high]==target) return high;
    else return -1;
}

  以上就是我们的二分查找算法,参考资料:数据结构与程序设计——C++语言描述(这真是一本好书!)

时间: 2024-08-09 19:52:29

二分查找--整理的相关文章

算法整理-二分查找和排序

1.  二分查找 (1) 有序数组查找插入位置:  主要是终止条件的判断,如果查找不到需要被范围的插入位置为begin public: int searchInsert(vector<int>& nums, int target) { int len = nums.size(); return binarySearch(nums, target, 0, len-1); } private: int binarySearch(vector<int>& nums, in

Java冒泡排序和二分查找(预习)

经查阅,将资料整理如下: 一.冒泡排序 1.算法简介 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成. 这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名. 2.算法原理 (1)比较相邻的元素.如果第一个比第二个大,就交换他们两个. (2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. (3)针对所有的元素重复以上的

STL中的二分查找———lower_bound,upper_bound,binary_search

关于STL中的排序和检索,排序一般用sort函数即可,今天来整理一下检索中常用的函数——lower_bound , upper_bound 和 binary_search . STL中关于二分查找的函数有三个lower_bound .upper_bound .binary_search .这三个函数都运用于有序区间(当然这也是运用二分查找的前提). Tips:1.在检索前,应该用sort函数对数组进行从小到大排序.     2.使用以上函数时必须包含头文件:#include < algorith

算法学习一~分治法~二分查找,快速的找~

现在编程也算是走上门了,但是没有把算法掌握下来只能说自己还是门外汉,所以以后我们就开始努力的学习算法,现在把自己每天的学习分享在这里希望大家能喜欢,并且我也要在这里整理我一天的学习和思路,. 二分查找..大家经常需要在一个数组中寻找某个值.如果是一个已经拍好序的话那么可以很快的找到.我们考虑下暴力查找,就是a[n],中找一个m,那么最好时是o(1),最差时是0(n),最终平均情况就是长度n/2.这样的时间复杂度不算很高但是可以改进到logn的级别. 1 #include<stdio.h>//算

LightOJ 1307 Counting Triangles 二分查找

[题解整理]二分题 题目类型: 二分查找: 二分答案. 大致解题思路: 查找注意有序和返回值: 浮点数注意精度: 整数注意返回值,建议另外维护一个变量,用于储存可行解. 题目 分类 传送门 WA点 poj 2785 二分查找 题解 lightoj 1088 二分查找 题解 lightoj 1307 二分查找 题解 longlong poj 2456 整数二分答案 题解 poj 3104 整数二分答案 题解 poj 3258 整数二分答案 题解 poj 3273 整数二分答案 题解 lightoj

用递归要小心---以递归二分查找为例

昨天面试的时候被问了好多问题,今天再做,有些部分竟然连起来了:二分查找.递归.局部变量静态变量(静态局部变量),可能还有更多,待我慢慢总结.. OK进入正题. 一. 首先 写个二分查找的函数.因为之前只是了解过这个算法,实际自己写还没写过,想了想,如果不用递归,一时没啥思路,那就用递归吧 // This is v0.1 and there may be errors. #include <stdio.h> int binary_search(int a[], int left, int rig

关于二分查找的总结

最近又重新拾起了一直很凌乱的二分查找,各种版本,有时候总是很难调对,今天就整理了一下. 最基础的二分查找是从非递减序的数组中查找某个元素是否在数组中,如果在的话,随意返回一个位置,如果没有这个元素,返回-1.那么就有了下面这个基础的算法 //查找目标元素在数组中的位置,任意一个都可以,如果没有返回-1 int Binary_search(int *arr, int n, int val) { int l = 0; int r = n - 1; while (l <= r) { int mid =

二分查找的那些坑

听说很多人写不对二分查找,如果不好好总结一下,我大概也会是其中之一.. 历史上二分查找的bug 二分查找虽然原理很简单,实现起来却有很多的坑. <编程珠玑>的作者做实验发现90%的人写不对二分查找,然后亲手在该书里写下一个带 bug 的 binary search... 据说该 bug 在书里呆了二十年没人发现,而这本书还是一本人人交手称赞的好书. 然后 java 标准库里,一个和<编程珠玑>同样的 bug 在 2006 年才被发现.. 那这个 bug 是啥呢?是一个很好理解的问题

基础排序、二分查找汇总

一.常见排序算法复杂度和稳定性 二.js代码实现和思路 (1)冒泡排序:从数组起始位置两两比较,前一个大于后一个就交换位置,第一轮比较后最大的那个数就排到了最后,循环比较数组长度-1次 function bubble (arr) { for (let j = 0; j < arr.length - 1; j++) { for (let i = 0; i < arr.length - 1 - j; i++) { if (arr[i] > arr[i + 1]) { [arr[i], arr