二分查找(Binary Search)
1.二分查找的介绍
二分查找(Binary Search)是一种用于在有序数组中快速查找特定元素的搜索算法。
它的核心思想是通过不断将搜索范围减半,来快速定位目标元素。
以下是详细的步骤:
初始化左右边界: 首先,确定搜索范围的左边界
left
和右边界right
。初始时,left
设置为数组的起始位置(通常是 0),right
设置为数组的末尾位置(数组长度减 1)。进入循环: 使用一个循环来不断缩小搜索范围,直到找到目标元素或确定它不存在。循环条件是
left
小于等于right
。计算中间索引: 在每次循环迭代中,计算中间索引
mid
,通常通过(left + right) / 2
来获取。这个索引指向当前搜索范围的中间元素。比较中间元素: 将中间元素与目标元素进行比较:
- 如果中间元素等于目标元素,那么找到了目标,返回
mid
。 - 如果中间元素小于目标元素,说明目标元素可能在右半部分,将
left
更新为mid + 1
。 - 如果中间元素大于目标元素,说明目标元素可能在左半部分,将
right
更新为mid - 1
。
- 如果中间元素等于目标元素,那么找到了目标,返回
重复步骤 3 和 4: 继续在新的搜索范围内执行步骤 3 和 4,直到找到目标元素或确定它不存在。
返回结果: 如果找到目标元素,返回它的索引;否则,返回 -1 表示未找到。
下面是一个 JavaScript 示例,演示如何实现二分查找:
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) {
return mid; // 找到了目标元素,返回索引
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右半部分
} else {
right = mid - 1; // 目标在左半部分
}
}
return -1; // 没有找到目标元素
}
总之,二分查找是一种高效的查找算法,特别适用于大型有序数组,
因为它可以在 O(log n) 的时间复杂度内找到目标元素,
其中 n 是数组的长度。这远比线性查找(O(n))要快。
但要注意,前提是数组必须是有序的,否则算法将无法正确工作。
2. 二分查找的示例
// 二分查找,寻找数字7的索引
const numArr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
/*******************************************************************************************************
* 1.找到中间的索引值 5分开,[1, 2, 3, 4] 5 [6, 7, 8, 9,10]
2.和中间的数字进行对比,需要找的数字7大于5,则在右边找
3.[6, 7] 8 [9, 10],找到中间的索引值8,需要找的数字7小于8,则在左边找
4.[6] ,7,找到中间的索引值7,找到
*/
function searchIndex(arr, searchValue, compareFn) {
compareFn = compareFn || function (a, b) { return a - b };
let firstIndex = 0, lastIndex = arr.length - 1;
while (firstIndex <= lastIndex) {
let middleIndex = Math.ceil((firstIndex + lastIndex) / 2);
const compareResult = compareFn(arr[middleIndex], searchValue);
if (compareResult === 0) {
return middleIndex
} else if (compareResult > 0) {
lastIndex = middleIndex - 1
} else if (compareResult < 0) {
firstIndex = middleIndex + 1
}
}
return -1
}
const index = searchIndex(numArr, 7);
console.log(index);
/*******************************************************************************************************
* 目前有数组50000个数据,ids:10000个,查找详情
*/
const arr = Array.from({ length: 50000 }, (item, idx) => {
return { id: idx, name: 'any string', age: 'random number' };
});
// [{id:0},{id:1},{id:2},{id:3},{id:4}]
const ids = Array.from({ length: 10000 }, (item, idx) => {
// 0~50000 之间的整数
return Math.ceil(Math.random() * 50000);
});
// [1,4,5]
function findDetail(arr, ids) {
// 查id的每个详细数据返回
if (!ids || !ids.length) {
return null;
}
const result = ids.map(id => {
const item = findItem(arr, id);
return item;
})
return result;
}
function findItem(arr, id) {
const index = searchIndex(arr, id, (item, id) => item.id - id);
return arr[index];
}
const listDetails = findDetail(arr, ids);
console.log(listDetails);