二分算法入门——二分查找

  二分查找,无论是从名字还是理论都十分简单一个算法,其博大精深,简直恐怖。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-10-19 23:23:33

二分算法入门——二分查找的相关文章

递归和二分算法

递归程序调用自身的编程方法称为递归(recursion) 它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量.递归的能力在于用有限的语句来定义对象的无线的集合.一般来说,递归需要有边界条件.递归前进段和递归返回段.当边界条件不满足时,递归前进:当边界条件满足时,递归返回. 递归的两个条件: 1,每一次的调用都会使问题的规模有所减少 2,必须有一个明确的终止条件 python中测试的递归

what&#39; the python之递归函数与二分算法

what's the 递归? 递归函数的定义:在函数里可以再调用函数,如果这个调用的函数是函数本身,那么就形成了一个递归函数. 递归的最大深度为997,这个是程序强制定义的,997完全可以满足一般情况下用到递归的情形. #最大997层 def foo(n): print(n) n += 1 foo(n) foo(1) 举个栗子,假设你想知道A的年龄,但你只知道A比B大2岁,B又比C大两岁,C又比D大两岁,D比E大两岁,恰好你知道E的岁数,那是不是就能知道A的岁数了呢,这就可以组成一个递归.那我们

对二分算法的理解及结对编程情况

一.对二分算法理解 二分算法,又称折半算法,是应用分治策略的典型例子.二分查找主要对有序序列进行对所指定数字的查找,通过不断缩小搜查范围,在比较中间的数后对左右两个数组进行相同操作,以得到最终的带查找数字.时间复杂度logn,对数组较大时能显著提高程序效率. 二.算法代码 #include <iostream>using namespace std;int main(){ int n,x; cin >> n; if(1<=n<=100){  int a[n];  for

python常用的简单算法,二分查找、冒泡排序、数组翻转等

1.二分查找:主要用于查询元素数量较多的列表,采用二分查找,取中位值,进行大小比较,可以提高效率 1 #二分查找,用于在较大的数据列表中查询某个值,考虑到元素比较多,单纯的遍历会造成内存压力过大,考虑使用二分查找 2 #二分查找的关键在于查询中间值,将需要查找的值与中间值进行比较,然后确定查找方向 3 def binary_search(data_source,find_n): 4 #取中位数 5 mid=int(len(data_source)/2) 6 7 if len(data_sourc

排序算法(冒泡,选择,插入,快速)查找算法(二分,快速)

四种排序算法 1.冒泡排序 思路分析:从前往后相邻的两个数一次进行比较,大的往下沉,小的网上 冒.当相邻的两个数的比较后发现他们的排序与排序要求相反,就互换. 代码实现 $arr = array (1,42,33,69,7,82,34,54,70,99); $len = count($arr); For($i=1;$i<$len;$i++){ For($j=0;$j<$len-$i;$j++){ If($arr[$j] > $arr[$j+1]){ $tmp = $arr[$j+1];

查找算法:二分查找、顺序查找

08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/details/7747205 查找算法 查找算法是在存在的序列(list) 中查找特定的目标(target),要求序列中每个记录必须与一个关键词(key)关联才能进行查找. 查找算法通常需要两个输入: 1.被查找的序列 2.要查找的关键词 查找算法的输出参数和返回值: 1.返回类型为 Error_co

【数据结构与算法】二分查找

基本思想 首先将给定的值K与表中中间位置元素比较,若相等,则查找成功:若不等,则所需查找的元素只能在中间数据以外的前半部分或者后半部分,缩小范围后继续进行同样的查找,如此反复,直到找到为止. 代码实现 /** * 源码名称:BinarySearch.java * 日期:2014-08-14 * 程序功能:二分查找 * 版权:[email protected] * 作者:A2BGeek */ public class BinarySearch { public static int binaryS

算法系列&lt;二分查找&gt;

二分查找又称折半查找,是针对有序顺序表的查找,前提:数据是顺序存储的,已经按照关键词进行升序排序.查找成功返回索引值,查找不成功返回-1. 下面用java来实现二分查找算法: /** * 二分查找:针对已排好序的序列,查找成功返回所在位置的索引值,查找不成功返回-1 * 查找的最好时间复杂度:O(1),最坏时间复杂度O(logN),平均时间复杂度:O(logN) * 测试case: * case1:{1} 查找1 * case2:{1} 查找2 * case3:{} 查找1 * case4:{1

算法学习——二分查找(折半查找)

算法学习--二分查找 注意点 1. 二分查找的前提是有序的数组 2. 建议使用[start,end)的区间寻找,符合规范 3. 使用的是递归法 递归的人口 private static int find(int[] temp, int x) { //如果要查找的数x比数组的最后一个数要大,则找不到数值,返回-1 if (x > temp[temp.length - 1]) { return -1; } return find(temp, 0, temp.length, x);//进入递归 } 递