二分查找(binary search)

二分查找又叫折半查找,要查找的前提是检索结果位于已排序的列表中。

概念

在一个已排序的数组seq中,使用二分查找v,假如这个数组的范围是[low…high],我们要的v就在这个范围里。查找的方法是拿low到high的正中间的值,我们假设是m,来跟v相比,如果m>v,说明我们要查找的v在前数组seq的前半部,否则就在后半部。无论是在前半部还是后半部,将那部分再次折半查找,重复这个过程,知道查找到v值所在的地方。
实现二分查找可以用循环,也可以递归,先给出两种方式的伪代码。

伪代码

使用循环实现

Iterative-Binary-Search(seq, v, low, high)
    while low <= high
        mid = (low + high) / 2
        if v == seq[mid]
            return mid
        elseif v > seq[mid]
            low = mid + 1
        else
            high = mid - 1
    return NIL

使用递归实现

Recursive-Binary-Search(seq, v, low, high)
    if low > high
        return NIL
    mid = (low + high) / 2
    if v == seq[mid]
        return mid
    elseif v > seq[mid]
        return Recursive-Binary-Search(seq,v,mid+1,high)
    else
        return Recursive-Binary-Search(seq,v,low,mid-1)

无论是循环还是递归,当数组为空的时候就结束(low > high),返回空值。当查找到v值的时候,也立即结束。

Python版

使用循环实现

def search(seq, v, low, high):
    while low <= high:
        mid = (low + high) // 2
        if v == seq[mid]:
            return mid
        elif v > seq[mid]:
            low = mid + 1
        else:
            high = mid - 1
    return None

使用递归实现

def search2(seq, v, low , high):
    if low > high:
        return None
    mid = (low + high) // 2
    if v == seq[mid]:
        return mid
    elif v > seq[mid]:
        return search2(seq, v, mid + 1, high)
    else:
        return search2(seq, v, low, mid - 1)

Python版源码: Github-Syler-Fun-Search-Python 

Java版

使用循环实现

    public static int search(int[] seq, int v, int low, int high) {
        while (low <= high) {
            int mid = (low + high) / 2;
            if (v == seq[mid]) {
                return mid;
            } else if (v > seq[mid]) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }

        return Integer.MIN_VALUE;
    }

使用递归实现

    public static int search2(int[] seq, int v, int low, int high) {
        if (low > high) {
            return Integer.MIN_VALUE;
        }
        int mid = (low + high) / 2;
        if (v == seq[mid]) {
            return mid;
        } else if (v > seq[mid]) {
            return search2(seq, v, mid + 1, high);
        } else {
            return search2(seq, v, low, mid - 1);
        }
    }

Java版源码: Github-Syler-Fun-Search-Java 
但是实际上呢,Java版应该写成这个样子
Arrays.binarySearch(int[] a, int fromIndex, int toIndex, int key)
Java源码中的二分查找是这个样子的:

    public static int binarySearch(int[] a, int fromIndex, int toIndex,
                                   int key) {
        rangeCheck(a.length, fromIndex, toIndex);
        return binarySearch0(a, fromIndex, toIndex, key);
    }

    // Like public version, but without range checks.
    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

所以呢,Java里就不用写二分查找算法,用自带的吧。

发表评论

电子邮件地址不会被公开。 必填项已用*标注