java.util.Arrays的BUG - 二分搜索算法

转载 2006年06月18日 16:12:00
Joshua Bloch, 获得过Jolt最畅销奖的《Effective Java》的作者, 是Sun Microsystems的杰出工程师和Transarc的资深系统设计师, J2SE 5.0 Tiger的代言人和领路人, 也是还是JSR166的发起人之一..

后来, Joshua Bloch去了Google, 成为了Google的首席工程师

Joshua Bloch拥有卡耐基.梅隆大学(CMU)计算机科学的博士学位。

在最近Joshua Bloch的一篇文章里, Joshua Bloch回忆了当年在CMU上课的时候, vividly Jon Bentley 第一节算法课, 就要求所有刚进来的PHD学生, 每人都写一个二分查找算法. 然后发现, 多数人的算法都存在BUG, 这在当时给了Joshua Bloch 一个很深的印象..

在之后, Joshua Bloch 负责java.util.Arrays 代码编写的时候, 采用了Bentley 在<<Programming Pearls >>一书中的二分查找算法, 结果在8年后的今天, Joshua Bloch 发现, 这里面原来还是有一个BUG.

问题到底是出在哪里? 竟然逃过了Bentley 和Joshua Bloch 的双重检测?

一起来看看java.util.Arrays的代码:

1:     public static int binarySearch(int[] a, int key) {
2:         int low = 0;
3:         int high = a.length - 1;
4:
5:         while (low <= high) {
6:             int mid = (low + high) / 2;
7:             int midVal = a[mid];
8:
9:             if (midVal < key)
10:                 low = mid + 1;
11:             else if (midVal > key)
12:                 high = mid - 1;
13:             else
14:                 return mid; // key found
15:         }
16:         return -(low + 1);  // key not found.
17:     }


这是很经典的一个二分查找算法.

bug出现在第6行:

6:             int mid =(low + high) / 2;

在一般情况下, 这个语句是不会出错的, 但是, 当low+high的值超过了最大的正int值 (231- 1) 的时候, mid会变成负值,  这个时候, 会抛出ArrayIndexOutOfBoundsException 异常..


所以当一个数组包含超过2的30次方 个元素的时候, 就很可能会带来问题... 当然, 在一般的应用里面, 很少数组会包含那么多元素, 但是现在这样的情况已经越来越多了, 比如Google的海量运算..

那如何解决这个问题?

很简单, 修改这行语句为:

6:             int mid = low + ((high - low) / 2);
或者
6:             int mid = (low + high) >>> 1;


在c或者c++中, 则可以如下实现:
6:             mid = ((unsigned) (low + high)) >> 1;


这个问题告诉我们, 无论什么时候, 我们都不要想当然我们的程序是完美的. 我们需要细心的设计,测试再测试,符合规范的方法等等...对此, 你有什么经验和大家分享吗?

同样给我们带来的思考是: 8年了, java.util.Arrays 竟然存在这样一个bug, 这不得不让我们对JDK本身的测试性, 稳定性 怀有疑问.. 将来又会有多少个类似的bug出现呢?

iOS开发中使用算法之二分搜索算法

本人是一名iOS开发程序猿,说实话在之前的开发项目中并没有到多少算法,算法对于本人也可以说是个硬伤。最近在找工作,面试官就会提到一些算法,由于不常用算法也就很难很好地回答面试的问题。由于之前学习过C以...
  • u010105969
  • u010105969
  • 2017年04月03日 21:11
  • 446

【算法设计与分析】3、二分搜索

/** * 书本:《算法分析与设计》 * 功能:二分搜索 * 1、设a[0:n-1]是一个已排好序的数组。请改写二分搜索算法,使得当搜索元素x不在数组中的时候,返回小于x的最大元素 * 的位置I和...
  • cutter_point
  • cutter_point
  • 2014年11月16日 18:40
  • 838

二分查找算法(Java)

今天在公司闲着蛋疼,网上瞎逛,偶然在InfoQ网站上看到一篇文章《计算机科学中最重要的32个算法》,原文地址:http://www.infoq.com/cn/news/2012/08/32-most-...
  • jackiehff
  • jackiehff
  • 2013年12月28日 14:42
  • 4981

【常用算法思路分析系列】与二分搜索相关高频题

本文是【常用算法思路分析系列】的第五篇,总结二分搜索相关的高频题目和解题思路。本文分析如下几个问题:1、求数组局部最小值问题;2、元素最左出现的位置;3、循环有序数组求最小值;4、最左原位;5、完全二...
  • shakespeare001
  • shakespeare001
  • 2016年06月12日 16:36
  • 2823

算法系列(二)查找算法--基本查找和二分查找

从n个元素中A0,A1....An-1中,找到要找到的元素x,最简单的方法是遍历n个元素,找到元素x则返回x的位置,这种算法的时间复杂度为O(n)。 如果这n个元素是有序的,我们不需要从头到尾遍历一遍...
  • robertcpp
  • robertcpp
  • 2016年05月29日 16:58
  • 5202

C++实现二分查找算法

想必二分查找很多人都不陌生,或许说很熟悉,但是在实际生活中又有很多人不能正确的写出它的相应代码,因为二分查找的边界条件等很难控制,下面我们来仔细的分析一下二分查找,这只是个人看法,如有异议,欢迎提出。...
  • Silence723
  • Silence723
  • 2016年07月27日 11:08
  • 3105

分治算法--二分搜索

二分查找:以有序表表示静态查找表时,查找函数可以用二分查找(binary search or half-intervalsearch )来实现。这种算法基于分治。...
  • ling_xiao007
  • ling_xiao007
  • 2015年08月03日 14:24
  • 1024

二分搜索算法

二分搜索算法 题目:设 a [ 0 : n - 1 ] 是一个已排好序的数组。请改写二分搜索算法,使得当搜索元素 x 不在数组中时,返回小于 x 的最大元素的位置 i 和大于 x 的最小元素位置 j...
  • u011506951
  • u011506951
  • 2014年06月26日 21:37
  • 1720

改写二分搜索算法

1.实践题目 改写二分搜索算法 2. 问题描述 设a[0:n-1]是已排好序的数组,请改写二分搜索算法,使得当x不在数组中时,返回小于x的最大元素位置i和大于x的最小元素位置j。当搜索元素在数组...
  • ZRP0708
  • ZRP0708
  • 2017年11月27日 20:49
  • 153

二分搜索算法

二分搜索算法是什么?规则是怎么定义的,估计时间久了,也会忘记,就是因为现在淡忘了,所以复习一下。无论我们走多远了,学过的东西,还是需要复习的...
  • love_jk
  • love_jk
  • 2014年02月27日 23:25
  • 811
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java.util.Arrays的BUG - 二分搜索算法
举报原因:
原因补充:

(最多只允许输入30个字)