C语言 二分查找 折半查找 算法详解

二分查找首先最最重要就是你要查询的目标数组是一个有序的数组

直接上代码

#include <stdio.h>
int binarysearch(int arr[], int size, int key) {
	int left = 0;
	int right = size - 1;
	while (left <= right) {
		int mid = (right + left) >> 1;
		if (key == arr[mid]) {
			return mid;
		}
		else if (key > arr[mid]) {
			left = mid + 1;
		}
		else if (key < arr[mid]) {
			right = mid - 1;
		}
	}
	return -1;
}
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int key = 0;
	printf("你要在1-9查找哪一个数字?\n");
	scanf_s("%d", &key);
	int num = binarysearch(arr, size, key);
	if (num) {
		printf("找到%d了!下标是%d", arr[num], num);
	}
	else {
		printf("没找到个数字!");
	}
	return 0;
}

来说第一种方式

主要就是这一句right = size -1;这个 我们要知道所有的运算其实都是下标运算如果是size - 1那就刚好匹配到数组下标每个数都可以找到,换而言之就是形成了一个左闭右闭的这个区间【left,right】

假设我们要找这个key为2

进入循环第一次

 之后我们的mid就是key了就直接返回了

为啥要每次循环是right = mid -1;呢 以为这个是闭区间也就是可以找到right然而mid在上一轮已经比过了所以没必要在进行一次所以说mid - 1

为啥在循环条件里面有等于号呢,举个特例如果key是1 or 9你没有等于号的话1和9是找不到的,其实他的根本原因是你right是size - 1的问题你就导致你的数组内是可以索引到的,那什么时候停止呢带等于号的话while(left <= right)当left == right + 1就停止了,带入数字看一下【8.7】不可能有个数字大于8小于7吧!

接下来来说第二种方式

#include <stdio.h>
int binarysearch(int arr[], int size, int key) {
	int left = 0;
	int right = size;
	while (left < right) {
		int mid = (right + left) >> 1;
		if (key == arr[mid]) {
			return mid;
		}
		else if (key > arr[mid]) {
			left = mid;
		}
		else if (key < arr[mid]) {
			right = mid;
		}
	}
	return -1;
}
int main() {
	int arr[] = { 1,2,3,4,5,6,7,8,9 };
	int size = sizeof(arr) / sizeof(arr[0]);
	int key = 0;
	printf("你要在1-9查找哪一个数字?\n");
	scanf_s("%d", &key);
	int num = binarysearch(arr, size, key);
	if (num) {
		printf("找到%d了!下标是%d", arr[num], num);
	}
	else {
		printf("没找到个数字!");
	}
	return 0;
}

这个主要是这一句right = mid 刚刚不是要减1吗这块咋又不减了?
是因为你right赋值是size 我们知道这个left 和 right mid 都是下标你数组原本最大的下标是size - 1你却给他个size 我直接 arr[right] 是越界的,换而言之也就是说这时候的范围是【left,right)左闭右开的,下一次循环的时候 mid 就被剔除出去了你的搜索区间就是【left,mid)和【mid + 1,rigth)你right = mid 其实也就是 mid下标的前一个元素来比较。

假设我们要找这个key为2

 

 

 最后arr[mid] == key找到了

这次循环退出的条件咋不能等于了while(left < right)那就是left == right 带入数字就是【8,8)你分开这个再去按照【left,mid)和【mid + 1,rigth)是空的找不了了。

然后就是这个算法的改进

也就是这一句

(right + left) >> 1

改成

left + ((right - left) >> 1);

来防止溢出 我们画个图来理解一下 

 前者就可能造成溢出问题 后者可能性就小 要是left + right 很大超过 int 的21亿多一点点范围呢,这个left + right 的值还准确吗?

时间复杂度:

 我们可以看出来O(\log2^N)

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五毛变向.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值