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

195 阅读1分钟

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

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

737fe6d7d1186ab5b85a12f72bede01.png

进入循环第一次

c3f775015d0e014d6e5022357bdde94.png

之后我们的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吧!

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

334c7992c85594d06856477dd9a9efd.png

213bcb3b570abcf0e198beff379bb5a.png

d1b81c10c57a8e997763a623e9daa46.png 最后arr[mid] == key找到了

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

然后就是这个算法的改进

也就是这一句

5364e5fe7db4f14f713373a58dfa3ce.png

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