C语言实现二分查找 && 求2个数的平均数,你可能没有注意到的细节

C语言实现二分查找,我相信很多朋友都会,但是这里面有一个小细节你可能没有注意到。本篇博客主要讲解:

  1. 二分查找的实现。
  2. 封装成函数。
  3. 求2个数的平均数的小细节。

C语言实现二分查找 && 求2个数的平均数,你可能没有注意到的细节_第1张图片

二分查找

二分查找指的是:在一个有序数组中查找一个指定的数据。比如一个数组存储的是1,2,3,4,5,6,7,8,9,10,这个数组是有序的,而我们想要在这里面查找一个数。

具体的玩法是:每次都找到中间元素,比较它和待查找元素,判断待查找元素在它左边还是右边。如果在左边,就去左边找,在右边就去右边找,具体的找法重复刚刚的步骤。

比如:还是刚刚的1~10的数组。我们想查找7。我们用left指代目前查找区间的左下标,right指代目前查找区间的右下标。一开始下标范围是0~9。

  1. left=0, right=9, mid=(0+9)/2=4, arr[4]=5<7,说明7在右边,下标区间缩小到5~9(其中5=mid+1)。
  2. left=5, right=9, mid=(5+9)/2=7, arr[7]=8>7,说明7在左边,下标区间缩小到5~6(其中6=mid-1)。
  3. left=5, right=6, mid=(5+6)/2=5, arr[5]=6<7,说明7在右边,下标区间缩小到6~6(其中6=mid+1)。
  4. left=6, right=6, mid=(6+6)/2=6, arr[6]=7,找到了。

可以发现,核心的逻辑就是,每次找到[left, right]范围中间元素arr[mid]和待查找的元素k进行比较,此时有3种情况:

  1. arr[mid]
  2. arr[mid]>k,说明k在左边,right=mid-1,left不变。
  3. arr[mid]==k,说明找到了。

注意必须时刻保证left<=right,否则这个区间是无效的,自然就找不到了。

这个逻辑的具体实现如下:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // 有序数组
	int sz = sizeof(arr) / sizeof(arr[0]); // 数组元素个数
	int k = 0; // 待查找元素
	scanf("%d", &k);

	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = (left + right) / 2;
		if (arr[mid] < k)
		{
			left = mid + 1;
		}
		else if (arr[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			printf("找到了,下标是:%d\n", mid);
			break;
		}
	}

	if (left > right)
	{
		printf("没找到%d\n", k);
	}

	return 0;
}

函数实现

将上面的逻辑改造成BinarySearch函数,如下:

int BinarySearch(int arr[], int sz, int k)
{
	int left = 0;
	int right = sz - 1;
	while (left <= right)
	{
		int mid = (left + right) / 2;

		if (arr[mid] < k)
			left = mid + 1;
		else if (arr[mid] > k)
			right = mid - 1;
		else
			return mid;
	}

	return -1;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // 有序数组
	int sz = sizeof(arr) / sizeof(arr[0]); // 数组元素个数
	int k = 0; // 要查找的数
	scanf("%d", &k);
	int ret = BinarySearch(arr, sz, k);
	if (ret == -1)
	{
		printf("找不到%d\n", k);
	}
	else
	{
		printf("找到了,下标是:%d\n", ret);
	}

	return 0;
}

求2个数的平均数

上面的逻辑中,有一行代码值得细说,那就是:

int mid = (left + right) / 2;

这是求2个数平均数的代码。这行代码其实有点小瑕疵,假设left和right都是21亿多一点,都没有超过int的最大值INT_MAX,但是加起来后就超过了,计算出来的结果会被截断。怎么解决这个问题呢?

int mid = left + (right - left) / 2;

这样就行了,和加起来除以2的结果是一样的,但是不存在越界的问题。

值得注意的是,/2的效果和>>1的效果是一样的。这可以类比,十进制的123右移一位得到12,恰好是123/10的结果。而>>操作符的运算速度会更快一些(不过也快不了多少),所以上面的代码也可以这样写:

int mid = left + ((right - left) >> 2);

注意这里面的两对括号都不能丢,因为操作符优先级的问题。

总结

  1. 二分查找指的是在一个有序数组中查找某个数据,可以每次找中间的数进行比较,每次将查找范围缩小一般,效率很高,时间复杂度为O(logN)。
  2. 求2个数的平均数,可以采取:a+((b-a)>>2)的方式。

感谢大家的阅读!

你可能感兴趣的:(C语言,c语言,算法,数据结构,二分查找,函数)