要点
- 递归 - 代码逻辑更加清晰
- 非递归 - 性能更好
- 时间复杂度O(logn) ——非常快
/**
* @description 二分查找
* @author lsr
*/
/**
* 二分查找 - 循环
* @param arr arr
* @param target 目标值
* @returns 目标值索引
*/
export function binarySearch1(arr: number[], target: number): number {
const length = arr.length
if (length === 0) return -1
let startIndex = 0
let endIndex = arr.length - 1
while (startIndex <= endIndex) {
const midIndex = Math.floor((startIndex + endIndex) / 2)
const midValue = arr[midIndex]
if (midValue > target) {
// 中间值大于目标值,则证明目标值在左边
endIndex = midIndex - 1
} else if (midValue < target) {
// 中间值小于目标值,则证明目标值在右边
startIndex = midIndex + 1
} else {
// 找到目标值
return midIndex
}
}
return -1
}
/**
* 二分查找 - 递归
* @param arr arr
* @param target 目标值
* @param startIndex 开始索引
* @param endIndex 结束索引
* @returns 目标值索引
*/
export function binarySearch2(
arr: number[],
target: number,
startIndex?: number,
endIndex?: number
): number {
const length = arr.length
if (length === 0) return -1
startIndex = startIndex || 0
endIndex = endIndex || arr.length - 1
if (startIndex > endIndex) return -1
const midIndex = Math.floor((startIndex + endIndex) / 2)
const midValue = arr[midIndex]
if (midValue > target) {
// 中间值大于目标值,则证明目标值在左边
return binarySearch2(arr, target, startIndex, midIndex - 1)
} else if (midValue < target) {
// 中间值小于目标值,则证明目标值在右边
return binarySearch2(arr, target, midIndex + 1, endIndex)
} else {
// 找到目标值
return midIndex
}
}
// 功能测试
// const arr = [10, 20, 30, 40, 50]
// const index = binarySearch1(arr, 30)
// console.log(index)
const arr = [10, 20, 30, 40, 50, 56, 67, 89, 90, 100, 134, 140, 150]
const target = 60
// const index = binarySearch2(arr, 31)
// console.log(index)
// 性能测试
console.time('binarySearch1')
for (let i = 0; i < 100 * 10000; i++) {
binarySearch1(arr, target)
}
console.timeEnd('binarySearch1') // 16.400634765625 ms
console.time('binarySearch2')
for (let i = 0; i < 100 * 10000; i++) {
binarySearch2(arr, target)
}
console.timeEnd('binarySearch2') // 36.666748046875 ms
单元测试
/**
* @description 二分查找 test
* @author lsr
*/
import { binarySearch1, binarySearch2 } from '@/01-algorithm/binary-search'
describe('二分查找 - 循环', () => {
it('空数组', () => {
const targetIndex = binarySearch1([], 100)
expect(targetIndex).toBe(-1)
})
it('目标值不存在', () => {
const arr = [10]
const targetIndex = binarySearch1(arr, 100)
expect(targetIndex).toBe(-1)
})
it('目标值存在', () => {
const arr = [10, 20, 30, 40, 50]
const targetIndex = binarySearch1(arr, 50)
expect(targetIndex).toBe(4)
})
})
describe('二分查找 - 递归', () => {
it('空数组', () => {
const targetIndex = binarySearch2([], 100)
expect(targetIndex).toBe(-1)
})
it('目标值不存在', () => {
const arr = [10]
const targetIndex = binarySearch2(arr, 100)
expect(targetIndex).toBe(-1)
})
it('目标值存在', () => {
const arr = [10, 20, 30, 40, 50]
const targetIndex = binarySearch2(arr, 50)
expect(targetIndex).toBe(4)
})
})
划重点
- 凡有序,必二分
- 凡二分,时间复杂度必包含O(logn)
- 递归 vs 非递归(非递归更快,递归逻辑更清晰,较真级别的对比)