天天看点

数据结构与算法:二分查找法—用最省内存方式实现快速查找

作者:日拱一卒程序猿

一、定义

二分查找(Binary Search)算法,也叫折半查找算法。

当我们要从一个序列中查找一个元素的时候,二分查找是一种非常快速的查找算法。

二分查找是针对有序数据集合的查找算法,如果是无序数据集合就用遍历查找。

数据结构与算法:二分查找法—用最省内存方式实现快速查找

二、本质

二分查找之所以快速,是因为它在匹配不成功的时候,每次都能排除剩余元素中一半的元素。

因此可能包含目标元素的有效范围就收缩得很快,而不像顺序查找那样,每次仅能排除一个元素。

三、思路

二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。

每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0。

数据结构与算法:二分查找法—用最省内存方式实现快速查找

三、案例

1、一个有序的数组中查找某个数字是否存在

/**
 * 二分法 标准
 */
public class HalfDemo1 {
    public static int binarySearch(int[] nums, int t) {
        //低位索引
        int low = 0;
        //高位索引
        int high = nums.length - 1;
        //中间索引
        int mid = 0;
        while (low <= high) {
           	// 使用(low+high)/2的话,如果low和high比较大,两者之和可能溢出
           // 除以2换成位运算>>1,可以提高效率
            mid =  low + ((high - low) >> 1);
            //等于半数
            if (t == nums[mid]) {
                return mid;
            }
           //半数以里
            else if (t < nums[mid]) {
                high = mid - 1;
            }
           //半数以外
            else {
                low = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        //有序数组
        int[] nums = {3, 12, 24, 31, 46, 48, 52, 66, 69, 79, 82};
        System.out.println(binarySearch(nums, 66));
    }
}

    /*
    递归实现
    */
// 二分查找的递归实现
    public int bsearch(int[] a, int n, int val) {
        return bsearchInternally(a, 0, n - 1, val);
    }

    private int bsearchInternally(int[] a, int low, int high, int value) {
        if (low > high) return -1;
        int  mid =  low + ((high - low) >> 1);
        if (a[mid] == value) {
            return mid;
        } else if (a[mid] < value) {
            return bsearchInternally(a, mid + 1, high, value);
        } else {
            return bsearchInternally(a, low, mid - 1, value);
        }
    }
           

四、局限性

1、首先,二分查找依赖的是顺序表结构,简单点说就是数组。

因为二分查找算法需要按照下标随机访问元素。

数组按照下标随机访问数据的时间复杂度是O(1),

而链表随机访问的时间复杂度是O(n)。

2、其次,二分查找针对的是有序数据。

如果数据没有序,我们需要先排序。

3、再次,数据量太小不适合二分查找。

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

4、最后,数据量太大也不适合二分查找。

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

五、应用

1、如何设计数据结构和算法,快速判断某个整数是否出现在这1000万数据中? 我们希望这个功能不要占用太多的内存空间,最多不要超过100MB。

每个数据大小是8字节,最简单的办法就是将数据存储在数组中,内存占用差不多是80MB,符合内存限制。

我们可以先对这1000万数据从小到大排序,然后再利用二分查找算法,

就可以快速地查找想要的数据了。