文章目录
欢迎讨论:如有错误或不足,欢迎指正和建议,本人主打“听劝”。当然,如有疑问,也期待你在评论区留言互动。
点赞+关注:如果这篇文章对你有帮助,那就支持一下小编吧~~
前言
二分查找(Binary Search)是一种经典的查找算法又称折半查找法,主要用于在有序数组中高效地查找目标值。其时间复杂度为 O ( log n ) O(\log n) O(logn),因此在大规模数据中非常实用。本文将结合一个 C 语言实现的代码,详细介绍二分查找的原理、代码实现。
简单的二分查找用例
1. 二分查找的基本原理
二分查找的核心思想是分而治之,通过不断缩小查找范围,快速定位目标值。假设我们有一个从小到大排序的数组,目标是查找一个特定的数字 k
。算法的步骤如下:
- 定义两个指针
left
和right
,分别指向数组的起始位置和末尾位置。 - 计算中间位置的下标
mid = (left + right) / 2
。 - 比较
arr[mid]
和k
的关系:- 如果
arr[mid] == k
,找到了目标值; - 如果
arr[mid] < k
,目标值在右半部分,将left
更新为mid + 1
; - 如果
arr[mid] > k
,目标值在左半部分,将right
更新为mid - 1
。
- 如果
- 重复上述步骤,直到找到目标值,或
left > right
时停止查找,表示目标值不存在。
2. 实现代码
以下是实现二分查找的完整代码:
#include<stdio.h>
int main() {
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 }; // 有序数组
int k; // 被查找的数
printf("请输入你要查找的数 (0-9):\n");
if (scanf("%d", &k) != 1 || k < 0 || k > 9) { // 检查输入合法性
printf("输入非法,请输入范围内的整数!\n");
return 1;
}
int left = 0;
int right = 9;
int mark = 0;
while (left <= right) {
int mid = left + (right - left) / 2; // 防止溢出的中间下标计算方式
if (arr[mid] < k) {
left = mid + 1;
} else if (arr[mid] > k) {
right = mid - 1;
} else {
printf("找到了,下标为 %d\n", mid);
mark = 1;
break;
}
}
if (!mark) {
printf("找不到\n");
}
return 0;
}
3. 代码详解
-
数组和目标值的定义:
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 }; // 有序数组 int k; // 被查找的数
arr
是一个有序数组,包含 10 个从 0 到 9 的整数。k
是用户需要查找的目标值。
-
输入检查:
if (scanf("%d", &k) != 1 || k < 0 || k > 9) { printf("输入非法,请输入范围内的整数!\n"); return 1; }
- 确保用户输入的值是整数,并且在数组范围内。如果不符合要求,直接返回错误提示。
-
查找逻辑:
int left = 0; int right = 9; int mark = 0; while (left <= right) { int mid = left + (right - left) / 2; if (arr[mid] < k) { left = mid + 1; } else if (arr[mid] > k) { right = mid - 1; } else { printf("找到了,下标为 %d\n", mid); mark = 1; break; } }
- 定义
left
和right
表示查找的范围。 mid
是当前中间元素的下标,比较其值与目标值k
。- 根据比较结果调整范围:
- 如果
arr[mid] < k
,目标值在右半部分; - 如果
arr[mid] > k
,目标值在左半部分; - 如果相等,则查找成功,打印结果。
- 如果
- 定义
-
查找结果:
if (!mark) { printf("找不到\n"); }
- 如果循环结束后
mark == 0
,表示未找到目标值。
- 如果循环结束后
4. 测试用例
输入测试
-
输入 5:
请输入你要查找的数 (0-9): 5 找到了,下标为 5
-
输入 10(超出范围):
请输入你要查找的数 (0-9): 10 输入非法,请输入范围内的整数!
-
输入 -1(非法输入):
请输入你要查找的数 (0-9): -1 输入非法,请输入范围内的整数!
-
输入不存在的值 8(如在 6 个数组中模拟):
请输入你要查找的数 ... printf log runtime ---- Check Trace Root
例题讲解
例子场景
你买了一双鞋,告诉我价格不超过 300 元,我想知道具体价格。我们假设价格是整数,范围在 0 到 300 之间(闭区间)。我每次猜一个数,你会告诉我是不是猜对了,或者价格更高还是更低。
解决方法
折半查找的核心思想是每次猜 中间数,这样可以最大限度地减少可能的范围。
分析过程
- 初始化范围:设
low = 0
和high = 300
。 - 每次取中点:计算
mid = (low + high) // 2
。 - 比较结果:
- 如果我猜的
mid
恰好是价格,则结束查找; - 如果
mid
小于真实价格,你会告诉我价格更高,于是更新范围:low = mid + 1
; - 如果
mid
大于真实价格,你会告诉我价格更低,于是更新范围:high = mid - 1
。
- 如果我猜的
- 循环继续:直到找到确切的价格。
实际操作
假设实际价格是 240 元,以下是折半查找的步骤:
- 初始范围:
low = 0
,high = 300
,mid = (0 + 300) // 2 = 150
。你说价格更高。 - 更新范围:
low = 151
,high = 300
,mid = (151 + 300) // 2 = 225
。你说价格更高。 - 更新范围:
low = 226
,high = 300
,mid = (226 + 300) // 2 = 263
。你说价格更低。 - 更新范围:
low = 226
,high = 262
,mid = (226 + 262) // 2 = 244
。你说价格更低。 - 更新范围:
low = 226
,high = 243
,mid = (226 + 243) // 2 = 234
。你说价格更高。 - 更新范围:
low = 235
,high = 243
,mid = (235 + 243) // 2 = 239
。你说价格更高。 - 更新范围:
low = 240
,high = 243
,mid = (240 + 243) // 2 = 241
。你说价格更低。 - 更新范围:
low = 240
,high = 240
,mid = (240 + 240) // 2 = 240
。猜中!
代码实现
#include <stdio.h>
int binarySearch(int low, int high, int target) {
int mid;
while (low <= high) {
mid = (low + high) / 2; // 计算中间值
printf("猜测的价格: %d\n", mid); // 显示猜测的价格
if (mid == target) {
printf("恭喜!找到价格: %d\n", mid);
return mid; // 找到目标价格
} else if (mid < target) {
printf("实际价格更高。\n");
low = mid + 1; // 调整范围到更高的一半
} else {
printf("实际价格更低。\n");
high = mid - 1; // 调整范围到更低的一半
}
}
printf("未找到价格。\n");
return -1; // 没有找到目标值
}
int main() {
int low = 0; // 最低价格
int high = 300; // 最高价格
int target = 240; // 实际价格(用于模拟)
printf("开始折半查找...\n");
binarySearch(low, high, target);
return 0;
}
优点分析
- 时间复杂度为 O ( log n ) O(\log n) O(logn),非常高效。
- 简单且容易实现。
结语
二分法的思想也常用于其他问题,如查找有序数组中的特定值或优化搜索空间问题。建议大家去深度学习。