前言科普

第一篇二分搜索论文是 1946 年发表,然而第一个没有 bug 的二分查找法却是在 1962 年才出现,中间用了 16 年的时间。

2019 年的你,在面试的过程中能手写出没有 bug 的二分查找法么?

定义

在计算机科学中,二分查找(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法

搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;

如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。

如果在某一步骤数组为空,则代表找不到。

这种搜索算法每一次比较都使搜索范围缩小一半。

二分查找法代码

按照上面的定义,我们来尝试写一下二分查找法的代码。

public static int binary(int[] arr, int data) {
        int min = 0;
        int max = arr.length - 1;
        int mid;
        while (min <= max) {
            mid = (min + max) / 2;
            if (arr[mid] > data) {
                max = mid - 1;
            } else if (arr[mid] < data) {
                min = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

现在问你,上面的代码有没有问题?哪段代码会出现 bug ?

请思考一分钟后再往下查看。

对于上面这段代码而言,问题出在第 6 行代码处:

mid = (min + max) / 2;

这句代码在 min 和 max 很大的时候,会出现溢出的情况,从而导致数组访问出错。

别看现在轻描淡写的指出了这个错误,但这个错误在当时可是存在了好些年。

那怎么改进呢?一般的做法是这样的:将加法变成减法。

public static int binary(int[] arr, int data) {
        int min = 0;
        int max = arr.length - 1;
        int mid;
        while (min <= max) {
            // 防止溢出
            mid =  min + (max - min) / 2;
            if (arr[mid] > data) {
                max = mid - 1;
            } else if (arr[mid] < data) {
                min = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

还有一种更高逼格的写法,也是官方的二分搜索法的实现写法:使用 位运算

 public static int binary(int[] arr, int data) {
        int min = 0;
        int max = arr.length - 1;
        int mid;
        while (min <= max) {
            // 无符号位运算符的优先级较低,先括起来
            mid =  min + ((max - min) >>> 1);
            if (arr[mid] > data) {
                max = mid - 1;
            } else if (arr[mid] < data) {
                min = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

希望通过今天的文章能帮助读者们在面试中手写对代码,毕竟,对于很多小公司来说,二分查找法会出现在他们的笔试题中的。

面试官,我会写二分查找法!对,没有 bug 的那种!的更多相关文章

  1. 二分查找法 java

    前几天去面试,让我写二分查找法,真是哔了狗! 提了离职申请,没事写写吧! 首先二分查找是在一堆有序的序列中找到指定的结果. public class Erfen { public static int ...

  2. 用c语言编写二分查找法

    二分法的适用范围为有序数列,这方面很有局限性. #include<stdio.h> //二分查找法 void binary_search(int a[],int start,int mid ...

  3. python 全栈开发,Day15(递归函数,二分查找法)

    一.递归函数 江湖上流传这这样一句话叫做:人理解循环,神理解递归.所以你可别小看了递归函数,很多人被拦在大神的门槛外这么多年,就是因为没能领悟递归的真谛. 递归函数:在一个函数里执行再调用这个函数本身 ...

  4. 二分查找法(java版)

    二分查找法也称为折半查找法,在有序的序列中使用二分法可以提高程序的执行效率. 典型的二分查找法代码 public int binarySearch1(int[] arr,int target){ in ...

  5. 二分查找法&大O表示法

    二分查找法的输入是一个有序的元素列表,如果要查找的元素包含在列表中,二分查找返回其位置,否则返回null Python代码(来源于<算法图解>一书): def binary_search( ...

  6. jvascript 顺序查找和二分查找法

    第一种:顺序查找法 中心思想:和数组中的值逐个比对! /* * 参数说明: * array:传入数组 * findVal:传入需要查找的数 */ function Orderseach(array,f ...

  7. java for循环和数组--冒泡排序、二分查找法

    //100以内与7相关的数   for(int a=1;a<=100;a++){    if(a%7==0||a%10==7||a/10==7){     System.out.print(a+ ...

  8. 学习练习 java 二分查找法

    package com.hanqi; import java.util.*; public class Test5 { public static void main(String[] args) { ...

  9. Java-数据结构与算法-二分查找法

    1.二分查找法思路:不断缩小范围,直到low <= high 2.代码: package Test; import java.util.Arrays; public class BinarySe ...

随机推荐

  1. Python连载54-FTP编程

    一.FTP工作流程 1.客户端链接远程主机上的FTP服务器 2.客户端输入用户名和密码(或者“anonymous”和电子邮件地址) 3.客户端和服务器进行各种文件传输和信息查询操作 4.客户端从远程F ...

  2. jQuery-文件上传问题解决

    后端要求文件上传需传参数为二进制流,用form-data方式传递,如下图所示: 为了满足该输入参数要求,上传代码如下: <input type="file" id=" ...

  3. freemarker从入门到精通

    目录 一:概述 二:Freemarker的Helloworld 三:freemarker模板语法 1.访问map中的key 2.访问POJO中的属性 3.取集合中的数据 4.判断 5.日期 6.Nul ...

  4. $和jquery的关系

    $和jquery的关系 $其实是jQuery的别名 一般直接使用$符号 在许多JavaScript库中都会有$作为标记.如果同时使用多个JavaScript库时难免会出现冲突. 解决方法:重新设置jQ ...

  5. 数据库在线导出工具:Adminer

    数据库在线导出工具:Adminer Adminer是一个类似PhpMyAdmin的MySQL客户端的"页面PHP",它只有一个PHP文件,包括:数据库的普通和函数操作等功能,是一个 ...

  6. Command CompileSwiftSources failed with a nonzero exit code

    Xcode错误提示:Command CompileSwiftSources failed with a nonzero exit code,网上找了好多才搞定,通过在Build Setting里面自添 ...

  7. Swift设置只读(readOnly)属性

    class ReadOnly { private(set) var name: String init(_ name: String) { self.name = name } } let obj = ...

  8. 详解 DNS 与 CoreDNS 的实现原理

    域名系统(Domain Name System)是整个互联网的电话簿,它能够将可被人理解的域名翻译成可被机器理解 IP 地址,使得互联网的使用者不再需要直接接触很难阅读和理解的 IP 地址. http ...

  9. volatile简记

    volatile指出变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错,也就是在使用变量时必须从它的地址中重新读取.

  10. ubuntu 或centos 使用Docker搭建anaconda+python基本环境

    ubuntu 16 使用Docker安装anacondaubuntu docker 安装centos docker 安装搜索可用镜像 docker search anaconda 拉取你中意的镜像 d ...