【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究

目录

前言

正文

总结


前言

今天学习到辅助工具类Collections的使用(注意Collection和Collections的区别,前者是一个接口,后者是一个工具类,可以帮助我们对集合进行排序或者查找等操作),Collections中有一个二分查找方法,在使用binarySearch()时,遇到了一些问题,通过查询资料了解到问题的原因,写一篇博客记录一下。


正文

这里直接使用ArrayList新建一个list对象,并向其添加0~9十个元素,然后使用shuffle()打乱一次顺序后,进行二分查找

package cn.hertter.collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestCollections {
    public static void main(String[] args) {
        List list = new ArrayList();
        for(int i = 0; i < 10; i++) {
            list.add(i);
        }
        
        System.out.println("原始的顺序:" + list);
        
        Collections.shuffle(list);
        System.out.println("打乱后顺序:" + list);
        
        System.out.println("二分查找20:" + Collections.binarySearch(list, 20));
        System.out.println("二分查找2:" + Collections.binarySearch(list, 2));
        
    }
}

 

结果很让我意外,20查不到很正常,但是返回的不是-1而是-11,且连2也查不到。
【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第1张图片

 

还是不敢相信,就又重新运行了一遍。

此时查找20的结果还是返回了-11,但是查找2却返回了-2。

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第2张图片

 

莫非,跟顺序有关系?突然想到之前学习的数据结构中,二分查找是有前提条件的!

二分查找必须在有序条件下,才能进行,否则会出错。

我尝试着把集合排一次序再来运行看看,即加上了Collections.sort(list);这一句代码并打印查看。

最终代码变成如下所示:

package cn.hertter.collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TestCollections {
    public static void main(String[] args) {
        List list = new ArrayList();
        for(int i = 0; i < 10; i++) {
            list.add(i);
        }
        
        System.out.println("原始的顺序:" + list);
        
        Collections.shuffle(list);
        System.out.println("打乱后顺序:" + list);
        
        Collections.sort(list);
        System.out.println("进行排序后:" + list);
        
        System.out.println("二分查找20:" + Collections.binarySearch(list, 20));
        System.out.println("二分查找2:" + Collections.binarySearch(list, 2));
        
    }
}

 

此时的结果有了变化!2查找到了!

但是又有一个新的问题:为什么查找20时,返回的不是-1而是-11呢?

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第3张图片

 

带着这个疑问,我去查看了binarySearch的源码,如下所示:

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第4张图片

 

其中还没看到具体的查找源码,我又查看了红圈中的源码,如下所示:

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第5张图片

 

大家注意看!其中红圈的部分,返回的是-(low + 1),我们模拟编译器进行一次编译看看!!

 

模拟编译:

第一次查找时:

    low = 0,high = 10 -1 = 9,mid = (9 + 0) / 2 = 4,这里的>>>1,就是除以2的意思

    cmp是根据mid与key(这里是我们要查找的20)进行对比

  •     若mid
  •     若mid>key,则返回1;
  •     若mid=key,则返回0

    因为4 < 20,所以这里的cmp等于-1。

第一次查找之后,low改变为5,下图可以帮助你们更好的理解。

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第6张图片

 

第二次查找时:

low = 5,high依然为9,mid = (9 + 5) / 2 = 7   

因为7 < 20,所以这里的cmp等于-1。

第二次查找之后,low改变为8,过程如下图所示。

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第7张图片

 

第三次查找时:

low = 8,high依然为9,mid = (9 + 8) / 2 = 8   

因为8 < 20,所以这里的cmp等于-1。

第三次查找之后,low改变为9,过程如下图所示。

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第8张图片

 

此时low仍然≤high,循环继续

第四次查找时:

low = 9,high依然为9,mid = (9 + 9) / 2 = 9   

因为9 < 20,所以这里的cmp等于-1。

第四次查找之后,low改变为10,循环结束!,过程如下图所示。

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第9张图片

 

此时,执行到最后一句,即return -(low + 1);

返回-(10 + 1),即返回-11,也正是我们之前查询的结果!

【Java入坑之路】关于Collections.binarySearch查找结果不符合预期的探究_第10张图片

原来查询不到时不一定返回-1!就像这里面一样,返回的是-11!!!


总结

在学习的过程中,可能会有惯性思维,即若查询不到结果,则返回-1,但是通过今天的探究,发现其实不然。

遇到具体问题需要具体分析,不能形成定性思维!

之前博主以为对二分查找比较熟悉了,但是今天还是遇到了问题,说到底还是基础掌握的不扎实!!!

因此,在今后的学习当中,需要不断巩固一下之前学习的知识,尽量避免在同一个坑中栽了多次!!!

你可能感兴趣的:(Java)