数据结构与算法之美-10 |二分查找

一、二分查找的思想

二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
二分查找的效率非常之高,时间复杂度为O(log(N)),这是一个相当惊人的时间复杂度。

二、二分查找的递归和非递归实现

一.递归实现

递归调用方法实现

二.非递归实现

while循环实现

三.递归和非递归的代码实现

package binarysearch;

public class binarySearchDemo {
   
     
    public static void main(String[] args) {
   
     
        //已经排好序的数组
        int[] MergeArray = {
   
     8, 11, 19, 23, 27, 33, 45, 55, 67, 98};//
        //需要寻找得值
        int tagret1 = 67;
        int tagret2 = 8;
        //排序方法
        binarySearchByRecursion(MergeArray, tagret2, 0, MergeArray.length - 1);

        binarySearchByWhile(MergeArray, tagret1, 0, MergeArray.length - 1);
    }

    //递归算法
    public static void binarySearchByRecursion(int[] MergeArray, int tagret, int indexlow, int indexhigt) {
   
     

        //1如果目标数据小于当前范围最小数据。2目标数据大于当前范围最大数据
        if (tagret > MergeArray[indexhigt] || tagret < MergeArray[indexlow]) {
   
     
            return;
        }
        int indexMiddle = indexlow + (indexhigt - indexlow) / 2;

        if (MergeArray[indexMiddle] > tagret) {
   
     
            binarySearchByRecursion(MergeArray, tagret, indexlow, indexMiddle - 1);
        } else if (MergeArray[indexMiddle] < tagret) {
   
     
            binarySearchByRecursion(MergeArray, tagret, indexMiddle + 1, indexhigt);
        } else if (MergeArray[indexMiddle] == tagret) {
   
     
            System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
        } else {
   
     
            System.out.println("目标数据不在数据范围内");
        }
    }

    //WHILE查找
    public static void binarySearchByWhile(int[] MergeArray, int tagret, int indexlow, int indexhigt) {
   
     

        if (indexlow > indexhigt) {
   
     
            return;
        }
        while (indexlow <= indexhigt) {
   
     

            int indexMiddle = indexlow + (indexhigt - indexlow) / 2;
            if (indexhigt == indexlow && indexhigt - indexlow == 0) {
   
     
                if (MergeArray[indexMiddle] == MergeArray[indexlow]) {
   
     
                    System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
                    return;
                }
            } else if (MergeArray[indexMiddle] > tagret) {
   
     
                indexhigt = indexMiddle - 1;
            } else if (MergeArray[indexMiddle] < tagret) {
   
     
                indexlow = indexMiddle + 1;

            } else if (MergeArray[indexMiddle] == tagret) {
   
     
                System.out.printf("找到目标数据" + MergeArray[indexMiddle]);
                return;
            } else {
   
     
                System.out.println("目标数据不在数据范围内");
                return;
            }
        }
    }
}

三、二分查找的易错点

一.循环退出条件

注意是low<=high,而不是 low

二.mid 的取值

改进的方法是将 mid 的计算方式写成 low+(high-low)/2。更进一步,如果要将性能优化到极致的话,可以将这里的除以 2 操作转化成位运算 low+((high-low)>>1)。

三.low 和 high 的更新

low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。比如,当 high=3,low=3 时,如果 a[3]不等于 value,就会导致一直循环不退出。

四、二分查找的局限性

一.二分查找依赖的是顺序表结构

二分查找只能用在数据是通过顺序表来存储的数据结构上。如果你的数据是通过其他数据结构存储的,则无法应用二分查找。

二.二分查找针对的是有序数据

二分查找对这一点的要求比较苛刻,数据必须是有序的。如果数据没有序,需要先排序。

三.数据量太小不适合二分查找

如果要处理的数据量很小,完全没有必要用二分查找,顺序遍历就足够了。比如我们在一个大小为 10 的数组中查找一个元素,不管用二分查找还是顺序遍历,查找速度都差不多。只有数据量比较大的时候,二分查找的优势才会比较明显。

四.数据量太大也不适合二分查找

二分查找的底层需要依赖数组这种数据结构,而数组为了支持随机访问的特性,要求内存空间连续,对内存的要求比较苛刻。比如有 1GB 大小的数据,如果希望用数组来存储,那就需要 1GB 的连续内存空间。

版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址: