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

转载 2006年06月10日 09:20: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出现呢?

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

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

最优化第二讲—一维搜索算法(二分法、等区间法)

本讲主要列一下单峰搜索算法
  • nwpuwyk
  • nwpuwyk
  • 2014年05月25日 17:04
  • 3397

物联12:二进制树型搜索算法

二进制树型搜索算法         纯ALOHA算法和时隙ALOHA算法的信道最佳利用率为18.4%和36.8%,随着标签数量的增加,其性能急剧恶化,因此人们提出了二进制搜索算法。二进制防碰撞算法基...
  • u013847155
  • u013847155
  • 2015年04月15日 10:43
  • 3055

java编写的几种搜索算法

  • 2015年07月14日 17:03
  • 49KB
  • 下载

关于util下的Arrays.sort引起的思考和内部实现的二叉树算法实践

今天在看常用类库的时候,看见了关于util包下的Arrays.sort内部的一个实现方式感觉蛮有深入了解的必要性的,初步了解要实现这个排序传入的参数需要实现Comparable或者Comparator...
  • zhenxiangxuehaojishu
  • zhenxiangxuehaojishu
  • 2016年05月25日 10:24
  • 203

深度优先搜索算法(java语言)

我们在学习了图之后,需要一种机制来遍历图,图的遍历算法也叫图搜索算法。与树的遍历算法(中序、前序、后序以及层序遍历)一样,图搜索算法也可以看做从图的某个源点开始,通过遍历和标记顶点来搜索图。下面讨论两...
  • alan_gaohaodong
  • alan_gaohaodong
  • 2017年12月24日 15:31
  • 41

【Java】利用单链表遍历、队列通过广度优先搜索算法来求各个的连通分量

这里就不再用书上的大堆废话的来说,广度优先搜索算法就是遍历一个图所有点的算法,也就说要对图中的每一个点进行访问,访问之后你才能对点进行操作。由于你对一个图进行操作,那么你必须对图上的每个点进行操作,所...
  • yongh701
  • yongh701
  • 2015年01月31日 22:40
  • 1260

基于禁忌搜索算法求解TSP问题(JAVA)

一、TSP问题 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他...
  • wangqiuyun
  • wangqiuyun
  • 2013年04月17日 22:38
  • 9137

【Java】八数码的宽度优先搜索算法及用户界面

算法部分: import java.util.*; public class EightNumPath { final static int dx[] = {-1, 1, 0, 0}; fina...
  • qq_27524749
  • qq_27524749
  • 2017年04月16日 16:41
  • 82

java.util.Arrays.asList使用体会

下面的代码执行后 private void onButtonAsListClick() { String[] strArray = new String[] { "aa", "bb" };...
  • gh102
  • gh102
  • 2012年02月28日 09:48
  • 6395
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java.util.Arrays的BUG - 二分搜索算法
举报原因:
原因补充:

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