当前位置:网站首页>CSDN21天学习挑战赛之折半查找
CSDN21天学习挑战赛之折半查找
2022-08-10 23:05:00 【进击的博仔】
活动地址:CSDN21天学习挑战赛
“九层之台,起于垒土”。学习技术须脚踏实地。
折半查找的概念
现代计算机和网络使我们能够访问海量的信息。高效 查找(检索) 这些信息的能力是处理它们的重要前提。
最简单的查找就是顺序查找,顺序查找就是对数据结构进行线性扫描,来查找满足要求的元素。
虽然顺序查找比较简单,但是它的时间复杂度是 O ( n ) O(n) O(n)。如果元素是在有序的前提下继续使用顺序查找就会显得得不偿失了,因为还有一种折半查找的算法专一应用于有序序列。
折半查找: 也叫二分查找,每次搜索都会将搜索的目标区间缩小一半,所以可以保证在 O ( l o g 2 n ) O(log_2n) O(log2n)的时间复杂度内完成查找。
1、折半查找
1.1 算法流程
输入
- n 个数的有序序列
a
,默认升序; - 待查找元素
key
。
- n 个数的有序序列
开始查找,每次循环确定待查找区间的中点索引
mid
,将 key 与 a[mid] 进行比较。- 若 key 与 a[mid] 相等:直接返回 mid;
- 若 key 大于 a[mid]:待查找区间变为当前查找区间的左侧半区间;
- 若 key 小于 a[mid]:待查找区间变为当前查找区间的右侧侧半区间。
如果查找过程中未返回 mid,则查找失败,返回 -1。
过程演示:
要查找的 key = 19
图片来源
1.2 C++实现
template<typename T>
int BinarySearch(T* a, int size, T key){
int lo = 0, hi = size - 1;
while(lo <= hi){
int mid = lo + (hi - lo) / 2;
if(key < a[mid]) hi = mid - 1;
else if(key > a[mid]) lo = mid + 1;
else return mid;
}
return -1;
}
循环控制条件解释:当lo = hi时,此处的元素还未与key进行比较,所以要设为 <=。
2、查找元素第一次与最后一次出现的位置
2.1 改进部分
首次出现:
hi = mid
找到下标时不返回,存入hi
, 逐步收缩右边界,找不到时则按照一般二分计算。循环结束条件。
退出前一步可能
mid = lo
或mid = (hi - lo) / 2
。mid = (hi - lo) / 2
时:- 如果 a[mid] = key,hi = mid,也就是下一种情况(
mid = lo
)。 - 如果 a[mid] < key,lo = hi,退出循环。
mid = lo
时:- 如果 a[mid] = key,hi = mid = lo,退出循环。
- 如果 a[mid] < key,lo = hi,退出循环。
综上,退出循环时总有 `lo = hi`,所以,循环结束条件如果设置成 <= 将会无限循环。- 如果 a[mid] = key,hi = mid,也就是下一种情况(
循环退出时还未判断 hi 处的值,所以
if (a[hi] == key)
用来判断上面循环未判断的hi
处的值是否等于key
。因为lo = hi
所以此处也可换为if (a[lo] == key)
。
最后出现:
利用**对称性(便于理解),类比上面的算法,很容易想到将
else hi = mid;
换成else lo = mid;
,将下标存入lo
,收缩左边界。但此时有一点不对称,就是计算
mid
时是取整计算,去掉小数点后的数,如果要对称的话就要在原始mid
的基础上加 1。即int mid = lo + (hi - lo) / 2 + 1;
2.2 C++实现
template<typename T>
int left(T* a, int size, T key) {
int lo = 0;
int hi = size - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (key < a[mid]) hi = mid - 1;
else if (key > a[mid]) lo = mid + 1;
else hi = mid;
}
if (a[hi] == key)
return hi;
return -1;
}
template<typename T>
int right(T* a, int size, T key) {
int lo = 0;
int hi = size - 1;
while (lo < hi) {
int mid = lo + (hi - lo) / 2 + 1;
if (key < a[mid]) hi = mid - 1;
else if (key > a[mid]) lo = mid + 1;
else lo = mid;
}
if (a[lo] == key) //或 hi
return lo;
return -1;
}
3、复杂度分析
- 时间复杂度:每次循环将查找范围缩小一半,所以时间复杂度为O(n)。
- 空间复杂度:只需要维护一个索引变量,所以为O(1)。
边栏推荐
猜你喜欢
随机推荐
Anroid 组件化构架设计:细说为何需要使用组件化提高工程编译速度
【Maui正式版】创建可跨平台的Maui程序,以及有关依赖注入、MVVM双向绑定的实现和演示
2.0966 铝青铜板CuAl10Ni5Fe4铜棒
MySQL学习笔记(1)——基础操作
小程序制作开发应遵循哪些原则?
PlaidCTF 2022 Amongst Ourselves: Shipmate writeup
Mysql's partial table master-slave construction and new table
二叉树 | 层序遍历 | leecode刷题笔记
mysql中的三大日志
HGAME 2022 Week2 writeup
ArcGIS应用基础知识
二叉树 | 代码随想录学习笔记
Configuring vim(7) from scratch - autocommands
Tencent Cloud Lightweight Application Server Configuration and Website Building Tutorial
风控逻辑利器---规则引擎
Lambda
RecyclerView上下滑动时,不调用onBindViewHolder 导致列表的item不刷新
自学软件测试不知道该如何学起,【软件测试技能图谱|自学测试路线图】
62.【彻底改变你对C语言指针的厌恶(超详细)】
CSAPP lab0 实验环境搭建