📜  可以在未排序的数组中应用二进制搜索吗(1)

📅  最后修改于: 2023-12-03 15:07:26.631000             🧑  作者: Mango

可以在未排序的数组中应用二进制搜索吗

在二进制搜索(Binary search)中,我们通常要求输入数组是已排序的,然后通过递归或者循环将大问题分解成小问题,以此来降低时间复杂度,这也是二进制搜索比顺序搜索(Sequential search)更高效的原因之一。

那么当我们碰到一个未排序的数组时,能否仍然使用二进制搜索呢?

答案是 不一定

虽然二进制搜索的前提条件是有序数组,但是如果我们对未排序的数组进行排序,然后再使用二进制搜索,这样做显然是可行的。但是前提是我们需要对数组进行排序,而排序本身需要花费 $O(nlogn)$ 的时间复杂度,因此我们需要权衡是否值得付出这样的代价。

如果我们不想对数组进行排序,我们仍然可以运用二进制搜索的思想,不过需要有所改进。

在未排序的数组中进行二进制搜索,我们可以将中心点与起始点和结束点进行比较,然后根据这个信息将问题分解成更小的问题。

具体的,假设当前正在搜索下标 $l$ 到 $r$ 的数组,我们首先求出中心点 $mid=(l+r)/2$。然后我们分三种情况考虑:

  1. 如果 $A[mid]==target$,那么显然搜索成功了,我们可以返回 $mid$;
  2. 如果 $A[mid]>=A[l]$(左边是有序的),那么我们判断 $target$ 是否在 $A[l]$ 到 $A[mid]$ 的区间内,如果是,那么我们继续在这个区间进行搜索;否则我们在右半部分继续进行搜索;
  3. 如果 $A[mid]<=A[r]$(右边是有序的),那么我们判断 $target$ 是否在 $A[mid]$ 到 $A[r]$ 的区间内,如果是,那么我们继续在这个区间进行搜索;否则我们在左半部分继续进行搜索。

这种搜索方法的时间复杂度为 $O(logn)$,与二进制搜索的时间复杂度一致。但是由于问题特殊,每一次搜索的区间不再相等,因此这个算法并不能准确地称之为二进制搜索,更准确的命名是“旋转数组搜索”(Rotated Array Search)。

下面是一个用 Python 实现的旋转数组搜索的例子:

def rotated_array_search(arr, target):
    l, r = 0, len(arr)-1
    while l <= r:
        mid = (l+r) // 2
        if arr[mid] == target:
            return mid
        
        if arr[mid] >= arr[l]:
            if arr[l] <= target < arr[mid]:
                r = mid-1
            else:
                l = mid+1
        else:
            if arr[mid] < target <= arr[r]:
                l = mid+1
            else:
                r = mid-1
    
    return -1

以上是关于可以在未排序的数组中应用二进制搜索的讨论,希望能够帮助大家更好地理解这个算法。