【追求卓越07】算法--二分查找

引导

经过前面几节排序内容,我们开始接触查找算法--二分查找。

二分查找的时间复杂度是O(logn),是一个非常高效的算法。虽然理解起来很容易,但是真正想要熟练掌握就没那么简单了。

二分查找

二分查找原理:

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功

这和我们的归并排序,快速排序的思想是不是很相似。

|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| include<stdlib.h> #include<stdio.h> #include<string.h> int binarysearch(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(a[mid] != value) { if(low >= high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,13,15,16,18,19,20}; printf("index = %d\n",binarysearch(a,10,16)); return 0; } |

分析:

通过上面代码的实现,我相信大家对二分查找有了一定的了解。但是心细的朋友肯定会发现,这个代码只能确认数组中是否有目标值,若有相同的元素,则不能确定返回第一个。

因此接下来我们再来练习一下二分法的几个变体:

  1. 查找第一个等于给定值的元素
  2. 查找最后一个等于给定值的元素
  3. 查找第一个大于给定值的元素
  4. 查找最后一个小于给定值的元素

其实3,4就是1和2前移或后移的问题,我们主要练习前两个。

|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| / *查找第一个等于给定值的元素* / int findfirstvalue(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(1) { if(low > high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; else { if(mid==0 || (a[mid-1] != value)) return mid; else high = mid - 1; } mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,15,15,15,18,19,20}; printf("index = %d\n",findfirstvalue(a,10,15)); return 0; } |

|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| / *查找最后一个等于给定值的元素* / int findlastvalue(int a[],int len , int value) { int low = 0; int high = len - 1; int mid = low + (high - low)/2; while(1) { if(low > high) return -1; if(a[mid] > value) high = mid - 1; else if(a[mid] < value) low = mid + 1; else { if(mid==0 || (a[mid+1] != value)) return mid; else low = mid + 1; } mid = low + (high - low)/2; } return mid; } int main() { int a[10] = {1,5,8,10,15,15,15,18,19,20}; printf("index = %d\n",findlastvalue(a,10,15)); return 0; } |

注意:二分查找虽然效率很高但是它受限很多,使用起来也不是很方便,主要有以下几个原因:

  1. 二分查找依赖于数组

我们知道数组在内存中是连续存储的,如果二分查找依赖于数组。这无疑给自己造成很大的局限性。因为当数据量很大时,也就说明需要一个很大的数组,这是一个很高的要求

  1. 二分查找依赖于数据的有序,并且静态

二分查找针对的数据时有序的。当面对的数组时无序的时候该怎么办呢?我们通过之前的排序算法可以知道,排序最快通用的时间复杂度是O(nlogn)。当数组没有频繁的插入删除操作,我们先排序再二分查找,这样也是可以接受的。但是当数组面临常插入和删除的操作时,就不太适用了。会导致事件复杂度上升。

总结

本章我们开始介绍了二分查找,分析了代码实现,以及一些二分查找的变体。也介绍了二分查找适合的场景以及局限性。二分查找依赖有序的数组,对于太大或太小的数组都不太适用(太小没必要,太大没有空间)。并且不适合频繁的数据插入和删除操作。

相关推荐
地平线开发者2 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮3 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者3 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考3 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx7 小时前
CART决策树基本原理
算法·机器学习
Wect7 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱8 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway14 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风14 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect14 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript