The Algorithms logo
算法
关于我们捐赠

指数搜索

P
/**
 * Exponential Search
 *
 * The algorithm consists of two stages. The first stage determines a
 * range in which the search key would reside if it were in the list.
 * In the second stage, a binary search is performed on this range.
 *
 *
 *
 */

function binarySearch(arr, value, floor, ceiling) {
  // Middle index
  const mid = Math.floor((floor + ceiling) / 2)

  // If value is at the mid position return this position
  if (arr[mid] === value) {
    return mid
  }

  if (floor > ceiling) return -1

  // If the middle element is great than the value
  // search the left part of the array
  if (arr[mid] > value) {
    return binarySearch(arr, value, floor, mid - 1)
    // If the middle element is lower than the value
    // search the right part of the array
  } else {
    return binarySearch(arr, value, mid + 1, ceiling)
  }
}

function exponentialSearch(arr, length, value) {
  // If value is the first element of the array return this position
  if (arr[0] === value) {
    return 0
  }

  // Find range for binary search
  let i = 1
  while (i < length && arr[i] <= value) {
    i = i * 2
  }

  // Call binary search for the range found above
  return binarySearch(arr, value, i / 2, Math.min(i, length))
}

export { binarySearch, exponentialSearch }

// const arr = [2, 3, 4, 10, 40, 65, 78, 100]
// const value = 78
// const result = exponentialSearch(arr, arr.length, value)
关于此算法

先决条件

问题陈述

给定一个包含 n 个元素的已排序数组,编写一个函数来搜索给定元素(目标)的索引。

方法

  • 搜索目标包含在其中的**范围**,通过将索引以 2 的幂递增。
  • 如果此范围存在于数组中,则在其上应用二分查找算法。
  • 否则返回 -1。

示例

arr = [1, 2, 3, 4, 5, 6, 7, ... 998, 999, 1_000]

target = 998
index = 0
1. SEARCHING FOR THE RANGE
index = 1, 2, 4, 8, 16, 32, 64, ..., 512, ..., 1_024
after 10 iteration we have the index at 1_024 and outside of the array 
2. BINARY SEARCH
Now we can apply the binary search on the subarray from 512 and 1_000.

注意:我们从 512 到 1_000 应用二分查找,因为在 i = 2^10 = 1_024 时,数组已结束,并且目标数字小于数组的最新索引(1_000)。

时间复杂度

最坏情况: O(log *i*),其中 *i* = index(位置)为目标。

最佳情况: O(*1*)

复杂度解释

  • 算法第一部分的复杂度为 O( log i ),因为如果 i 是目标在数组中的位置,则在将搜索索引加倍 ⌈log(i)⌉ 次后,算法将位于大于或等于 i 的搜索索引处。我们可以写 2^⌈log(i)⌉ >= i
  • 算法第二部分的复杂度也为 O ( log i ),因为它是一个简单的二分查找。二分查找的复杂度(如此处所述)为 O( n ),其中 n 是数组的长度。在指数搜索中,算法应用的数组长度为 2^i - 2^(i-1),换句话说,即“(从开始到 i 的数组长度) - (跳过到前一次迭代的部分)”。很容易验证 2^i - 2^(i-1) = 2^(i-1)

经过详细解释后,我们可以说指数搜索的复杂度为

O(log i) + O(log i) = 2O(log i) = O(log i)

二分查找与指数搜索

让我们用一个不太理论的例子来看看这个比较。假设我们有一个包含 1_000_000 个元素的数组,我们想要搜索位于第 4 个位置的元素。很容易看出

  • 二分查找从数组的中间开始,经过多次迭代后到达第 4 个位置。
  • 指数搜索仅经过 2 次迭代即可到达第 4 个索引。