当前位置: 首页 > news >正文

二分查找:高效搜索有序数组

一.引入

我买了一件衣服,你好奇问我多少钱,我说不超过300元,你会怎么猜呢?你会1,2,3,4...这样猜吗?显然并不会;⼀般大家都会猜中间的数字,⽐如:150,然后看是大了还是小了,再接着猜...... 这样通过每次缩小一半的查找范围来寻找最终的值,就是二分查找,也叫折半查找

有序的数组中查找某个数就可以用二分查找(折半查找)

二分查找是一种非常高效的算法,相比于线性查找的 O(n) 时间复杂度,二分查找的时间复杂度为 O(log n) ,在处理大量数据时效率非常高

(对于时间复杂度的介绍见:时间复杂度_o(n)-CSDN博客)


二. 算法思路

2.1 查找过程演示

下面有一个有序的数组,现在要查找数字 “7”

数组:1 2 3 4 5 6 7 8 9 10

下标:0 1 2 3 4 5 6 7 8 9

查找过程如下:

1. 下标 (0+9) / 2 = 4,对应数字 5 < 7,将下标范围缩小至 5~9

2. 下标 (5+9) / 2 = 7,对应数字 8 > 7,将下标范围缩小至 5~6

3. 下标 (5+6) / 2 = 5,对应数字 6 < 7,将下标范围缩小至 6

4. 下标 6 对应要查找的数字 7,查找成功

2.2 逻辑化思路

1. 找出数组的中间元素 <--- 计算出中间元素 mid 的下标 <--- 定义左右下标 (left、right) ,取中值

2. 比较中间元素与要查找元素 k 的大小,若 mid > k ,则更新 right = mid - 1 ;若 mid < k ,则更新 left = mid + 1 

3. 由于每次查找的过程是重复的,因此我们将查找的过程放到一个 while 循环里面;循环条件是   left <= right 

4. 查找的结果有两种:查找成功 or 未查询到,因此我们设置一个标志变量 flag = 0; ,若查找成功,就将 flag = 1 ;循环结束后只要判断 flag 是否为 1,即可知道查找成功与否

以上就是二分查找的整体思路,下面让我们来写代码吧


三. 代码演示

3.1 初代码

#include <stdio.h>int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 0;scanf("%d", &k);//输入要查找的数字int sz = sizeof(arr) / sizeof(arr[0]);//定义左右下标及中间元素下标int left = 0;int right = sz - 1;int mid = 0;int flag = 0;//标志变量,0未查询到,1查找成功while (left <= right){mid = (left + right) / 2;if (arr[mid] < k){left = mid + 1;}else if (arr[mid] > k){right = mid - 1;}else{//查找成功,跳出循环flag = 1;break;}}if (flag == 1){printf("查找成功,下标为%d\n", mid);}else{printf("查找失败\n");}return 0;
}

3.2 优化点---计算平均值

当数字非常大时,left + right 很有可能越界,导致算得的中间值 mid 出错,因此我们换一种求平均值的方法: int  mid = left + (right - left) / 2; 。因为输入的 left、right 没有越界,而 left + (right - left) / 2 < right,所以就避免了越界这一问题

3.3 优化代码

#include <stdio.h>int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int k = 0;scanf("%d", &k);//输入要查找的数字int sz = sizeof(arr) / sizeof(arr[0]);//定义左右下标及中间元素下标int left = 0;int right = sz - 1;int mid = 0;int flag = 0;//标志变量,0未查询到,1查找成功while (left <= right){//mid = (left + right) / 2;mid = left + (right - left) / 2;//优化处if (arr[mid] < k){left = mid + 1;}else if (arr[mid] > k){right = mid - 1;}else{//查找成功,跳出循环flag = 1;break;}}if (flag == 1){printf("查找成功,下标为%d\n", mid);}else{printf("查找失败\n");}return 0;
}

结语

通过本文你将对二分查找有一个更好的了解,代码就是这样在不断地改进中优化的,有任何问题或建议欢迎留言讨论~

http://www.dtcms.com/a/311441.html

相关文章:

  • 【论文笔记】Multi-Behavior Graph Neural Networks for Recommender System
  • 深度学习loss总结(二)
  • [硬件电路-116]:模拟电路 - 信号处理电路 - 程控增益放大器
  • Batch Normalization(BN):深度学习中的“训练加速器”与实践指南
  • LLM Prompt与开源模型资源(3)如何写一个好的 Prompt
  • 【转】大模型安全治理的现状与展望
  • 【REACT18.x】使用vite创建的项目无法启动,报错TypeError: crypto.hash is not a function解决方法
  • SpringCloud实战:机器人对战系统架构
  • 【LeetCode 热题 100】739. 每日温度——(解法一)单调栈+从右到左
  • STL 算法与迭代器终极指南:从基础到高级应用
  • 函数指针——回调函数
  • 文件同步神器-rsync命令讲解
  • ESP32- 项目应用1 智能手表之功能补全 #5
  • UDP通信中BIND端口号的作用解析,LOCALPORT的关系解析
  • 代码随想录刷题Day23
  • verilog的学习
  • 高效游戏状态管理:使用双模式位运算与数学运算
  • 从基础功能到自主决策, Agent 开发进阶路怎么走?
  • 技巧|SwanLab记录ROC曲线攻略
  • VueX进阶Pinia
  • go idea goland debug 报错 no debug info found
  • 从递归到动态规划-解码方法
  • Json Jsoncpp
  • 深入 Go 底层原理(十四):timer 的实现与高性能定时器
  • python JSONPath 表达式生成器
  • 淘宝获取商品SKU详情API接口操作指南
  • 交互 Codeforces Round 1040 Interactive RBS
  • 开发指南128-基础类-BaseDAO
  • 力扣面试150题--回文数
  • ABP VNext + NATS JetStream:高性能事件流处理