Tiven

Tiven

博观而约取,厚积而薄发

天问的个人网站(天问博客),专注于Node.js、Vue.js、React、Vite、Npm、Nginx等大前端技术。不断学习新技术,记录日常开发问题,持续分享coding,极客开源,共同进步。生命不息,奋斗不止... [ hexo blog ]

【数据结构与算法】(9):二分查找


二分查找 也是比较常见的一个算法,本文就分别使用 循环递归 的形式实现二分查找。

数据结构与算法 · 二分查找

一、问题描述

给定一个可排序的数组,找到其中值为 targetindex 位置。

示例 1:

  • 输入:[1,2,3,4,5,6,7,8,9] , target=7
  • 输出:c

示例 1:

  • 输入:[300, 400, 500, 600, 700, 800, 900] , target=500
  • 输出:2

二、代码演示

  1. 二分查找 循环,性能更好
function binarySearch1(arr: number[], target: number):number {
  const len = arr.length;
  if (len === 0) return -1;

  let startIndex = 0;
  let endIndex = len - 1;

  while (startIndex <= endIndex) {
    const midIndex = Math.floor((startIndex + endIndex) / 2);
    const midValue = arr[midIndex]
    if (target < midValue) {
      // 目标值较小,在左侧继续查找
      endIndex = midIndex - 1;
    } else if (target > midValue) {
      // 目标值较大,在右侧继续查找
      startIndex = midIndex + 1;
    } else {
      // 相等
      return midIndex;
    }
  }

  return -1;
}
  1. 二分查找 递归,代码更清晰更简洁
function binarySearch2(arr: number[], target: number, startIndex?: number, endIndex?: number):number {
  const len = arr.length;
  if (len === 0) return -1;

  if (startIndex == null) startIndex = 0
  if (endIndex == null) endIndex = len - 1

  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
  }
}

三、性能测试

分别用 循环递归 二分查找的方法,对 [10, 20, 30, 40, 50, 60] ; target=20 ,进行 100万次 的查找测试。

let arr2 = [10, 20, 30, 40, 50, 60]

console.time('binarySearch1')
for (let i = 0; i < 100 * 10000; i++) {
  binarySearch1(arr2, 20)
}
console.timeEnd('binarySearch1')

console.time('binarySearch2')
for (let i = 0; i < 100 * 10000; i++) {
  binarySearch2(arr2, 20)
}
console.timeEnd('binarySearch2')

<div> <button style='padding: 10px 20px; color: #00b1fb;' class='rotate-btn' onclick='run()'>运行</button> <br> <b>binarySearch1 run time:</b> <span style='color: red;' class='box1-ms'>0</span> <hr> <b>binarySearch2 run time:</b> <span style='color: red;' class='box2-ms'>0</span> <hr> </div> <script> // 二分查找 循环 function binarySearch1(arr, target) { const len = arr.length; if (len === 0) return -1;

let startIndex = 0;
let endIndex = len - 1;

while (startIndex <= endIndex) {
  const midIndex = Math.floor((startIndex + endIndex) / 2);
  const midValue = arr[midIndex]
  if (target < midValue) {
    // 目标值较小,在左侧继续查找
    endIndex = midIndex - 1;
  } else if (target > midValue) {
    // 目标值较大,在右侧继续查找
    startIndex = midIndex + 1;
  } else {
    // 相等
    return midIndex;
  }
}
return -1;

}

// 二分查找 递归 function binarySearch2(arr, target, startIndex, endIndex) { const len = arr.length; if (len === 0) return -1;

if (startIndex == null) startIndex = 0
if (endIndex == null) endIndex = len - 1

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
}

}

let arr2 = [10, 20, 30, 40, 50, 60]

function run() { let s1 = performance.now() for (let i = 0; i < 100 * 10000; i++) { binarySearch1(arr2, 20) } document.querySelector('.box1-ms').innerText = performance.now() - s1 + ' ms'

let s2 = performance.now()
for (let i = 0; i < 100 * 10000; i++) {
  binarySearch2(arr2, 20)
}
document.querySelector('.box2-ms').innerText = performance.now() - s2 + ' ms'

} </script>

通过运行得知二分查找 循环递归 的执行效率相差无几。但是 循环 形式的二分查找避免了函数的多次调用,因此更胜一筹。

四、总结

  • 凡有序,必二分
  • 凡二分,时间复杂度必包含 O(logn)
  • 都可以使用递归和循环

《数据结构与算法》系列

  1. 什么是算法复杂度
  2. 堆(heap)、栈(stack)、队列(queue)
  3. 把一个数组旋转k步
  4. 判断字符串是否括号匹配
  5. 数组、栈、链表、队列结构与对比
  6. 用两个栈实现一个队列
  7. 反转单向链表
  8. 用链表实现队列
  9. 二分查找
  10. 查找两数之和

欢迎访问:天问博客