前言
今天我们来看一下经典查找元素方式——二分法
样例输出
使用二分法,对元素进行查找(输入要排查的有有序数组和该元素,输出该元素在数组中索引号)
示例1:
输入:
arr = [10, 20, 30, 40, 50]
target = 40
输出:
indx = 3
示例2:
输入:
arr = [10, 20, 30, 40, 50]
target = 400
输出:
indx = -1
解题思路
方法一(循环)
代码实现
export function binarySearch1(arr: number[], target: number): number {
const length = arr.length
if (length === 0) return -1
let startIndex = 0
let endIndex = length - 1
let midIndex = 0
let midValue = 0
while (startIndex <= endIndex) {
midIndex = Math.floor((startIndex + endIndex) / 2)
midValue = arr[midIndex]
if (target < midValue) {
// 小于预期值说明应该向左排查
endIndex = midIndex - 1
} else if (target > midValue) {
// 大于预期值说明应该向右排查
startIndex = midIndex + 1
} else {
// 相等输出结果
return midIndex
}
}
return -1
}
方法二(递归)
代码实现
export function binarySearch2(arr: number[], target: number, startIndex?: number, endIndex?: number): number {
const length = arr.length
if (length === 0) return -1
// 开始和结束的范围
if (startIndex == null) startIndex = 0
if (endIndex == null) endIndex = length - 1
// 如果 start 和 end 相遇,则结束
if (startIndex > endIndex) return -1
// 中间位置
const midIndex = Math.floor((startIndex + endIndex) / 2)
const midValue = arr[midIndex]
if (target < midValue) {
// 目标值较小,则继续在左侧查找
return binarySearch2(arr, target, startIndex, midIndex - 1)
} else if (target > midValue) {
// 目标值较大,则继续在右侧查找
return binarySearch2(arr, target, midIndex + 1, endIndex)
} else {
// 相等,返回
return midIndex
}
}
性能测试
通过性能测试我们可以判断出,循环的性能更好。
// // 性能测试
// console.time('binarySearch1')
// for (let i = 0; i < 100 * 10000; i++) {
// binarySearch1(arr, target)
// }
// console.timeEnd('binarySearch1') // 17ms
// console.time('binarySearch2')
// for (let i = 0; i < 100 * 10000; i++) {
// binarySearch2(arr, target)
// }
// console.timeEnd('binarySearch2') // 34ms
为什么循环的性能会更好,因为递归每次都要重新调用一遍原函数,所以性能偏低
单元测试
describe('二分查找', () => {
it('正常情况', () => {
const arr = [10, 20, 30, 40, 50]
const target = 40
const index = binarySearch1(arr, target)
expect(index).toBe(3)
})
it('空数组', () => {
expect(binarySearch1([], 100)).toBe(-1)
})
it('找不到 target', () => {
const arr = [10, 20, 30, 40, 50]
const target = 400
const index = binarySearch1(arr, target)
expect(index).toBe(-1)
})
})