用二分查找对一个已经顺序排好的数组进行查找的效率非常高。具体有多高呢,它的时间复杂度为O(Logn), 也就是说,对于一个有100个元素的数组,它可以在7次内给出结果。

下面我们给出二分查找的递归和循环的算法描述,并给出Go语言的实现。

递归版本的算法描述:

1. 如果数组为空,那么返回-1
2. 如果数组中间的元素等于Target,那么返回元素下标;
   如果大于,那么在前半个数组中用二分查找;反之,
   则在后半个数组中用二分查找

go语言实现:

func binarySearch(list []int, target int, offset int) int {
	low, high := 0, len(list)-1
	if low > high {
		return -1
	}

	mid := (low + high) / 2
	if list[mid] == target {
		return mid + offset
	}
	if list[mid] > target {
		return binarySearch(list[:mid], target, 0)
	} else {
		return binarySearch(list[mid+1:], target, offset+mid+1)
	}
}

说完了递归版本的算法,现在我们来看循环版本的。我们知道在很多情况下, 递归和循环是可以相互转化的,两者的关键都是在于终止条件。

对于二分查找来说,递归版本的终止条件为数组的长度为0;而对于它的 循环版本,终止条件则是下限low大于上限high。下面给出循环版本的算法 及实现。

循环版本的算法描述:

1. 定义low为0,high为数组长度减1
2. 遍历数组list,条件为low小于等于high,定义mid为(low + high) / 2,
   如果list[mid]等于Target,那么返回mid;如果list[mid]大于Target,
   则更新high为mid-1;反之,更新low为mid+1
3. 没有找到Target,返回-1

go语言实现:

func binarySearchLoop(list []int, target int) int {
    low, high := 0, len(list)-1
    for low <= high {
        mid := (low + high) / 2
        if list[mid] == target {
            return mid
        }
        if list[mid] > target {
            high = mid - 1
        } else {
            low = mid + 1
        }
    }
    return -1
}

以上。