二分法查找的bug与解决

来源:互联网 发布:unity3d素材免费资源 编辑:程序博客网 时间:2024/05/23 19:18

代码需求如下:

/* 
* 二分法查找操作:使用二分法查找有序数组中元素。找到返回索引,不存在 输出-1。
* 分析:二分法查找的前提是数组有序。
* 假如有一组数为3,12,24,36,55,68,75,88要查给定的值24.可设三个变量front
* ,mid,end分别指向数据的上界,中间和下界,mid=(front+end)/2.  
*/

原始代码如下:

public class Test29{public static void main(String[] args){int[] arr = {3,12,24,36,55,68,75,88};Arrays.sort(arr);//数组上界、下界、中间值int front = 0;int end = arr.length-1;int mid = 0;Scanner sc = new Scanner(System.in);System.out.println("请输入要查找的整数:");//输入5出现Bug,why?  front=0,end=1 进入死循环int num = sc.nextInt();//记录查询次数int count = 0;//输入数据是否存在于数组中,true表示存在,false表示不存在boolean flag = false;while(front <= end){count++;/* if(front > end){//front不可能大于endbreak;} */mid = (front + end) / 2;if(num > arr[mid]){front = mid;}else if(num == arr[mid]){flag = true;break;}else{end = mid;}}if(flag){System.out.println("该数据位于数组索引" + mid + "处," + "查找次数:" + count);}else{System.out.println("-1," + "查找次数:" + count);}}}
这段代码写完之后,粗看没发现什么bug,但是测试的时候出现了问题,输入数字5之后进入了死循环。此时front=0,end=1。此时开始反推逻辑,其实在if的第二个分支,已经将输入的数值与中间值进行了比较,所以需要将插入的索引位置前移或后移。如果不进行这种操作,那么就很可能进入一直与中间值比较的情况,从而进入死循环。

于是翻看了Arrays类下面的二分法查找源码:

private static int binarySearch0(int[] a, int fromIndex, int toIndex,                                     int key) {        int low = fromIndex;        int high = toIndex - 1;        while (low <= high) {            int mid = (low + high) >>> 1;            int midVal = a[mid];            if (midVal < key)                low = mid + 1;            else if (midVal > key)                high = mid - 1;            else                return mid; // key found        }        return -(low + 1);  // key not found.    }
很明显,源码在进行中值操作的时候,进行了前移(high = mid - 1)或后移( low = mid + 1),这样就避免了进入无限与中值比较的情况。

修改代码如下,问题解决:

import java.util.Arrays;import java.util.Scanner;public class Test29{public static void main(String[] args){int[] arr = {3,12,24,36,55,68,75,88};Arrays.sort(arr);//数组上界、下界、中间值int front = 0;int end = arr.length-1;int mid = 0;Scanner sc = new Scanner(System.in);System.out.println("请输入要查找的整数:");//输入5出现Bug,why?  front=0,end=1 进入死循环int num = sc.nextInt();//记录查询次数int count = 0;//输入数据是否存在于数组中,true表示存在,false表示不存在boolean flag = false;while(front <= end){count++;/* if(front > end){//front不可能大于endbreak;} */mid = (front + end) / 2;if(num > arr[mid]){front = mid + 1;}else if(num == arr[mid]){flag = true;break;}else{end = mid - 1;}}if(flag){System.out.println("该数据位于数组索引" + mid + "处," + "查找次数:" + count);}else{System.out.println("-1," + "查找次数:" + count);}}}