假设我们要查找一串数字,这串数字有16个数:1-16。怎么查找能找到自己想要的数字呢?

我们首先可以尝试遍历算法:

#include <stdio.h>
int main()
{
	int arr[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
	int sz = sizeof(arr) / sizeof(arr[0]);
  //sizeof数组名表示整个数组的大小,
  //除以数组第一个元素的大小得到的就是数组的长度。
	int i = 0;
	int n = 0;//n是我们要输入想要查找的数字
	scanf("%d", &n);

	for (i = 0; i < sz-1; i++)
  //因为数组下标是从0开始的,所以数组中最大的下标应该是最大值-1
	{
		if (arr[i] == n)
		{
			printf("找到了这个数字的下标是:%d\n", i);
			break;
		}
	}
	if (i >= 16)
	{
		printf("数组中没有这个数字\n");
	}
	return 0;
}

运行结果如下:

C语言二分查找_数组



但是这是数字少,如果数字大呢?1W个数字,100W个数字呢?程序需要运行很长时间。

所以我们采用新的方法——折半查找(二分查找)

C语言二分查找_赋值_02

折半查找的逻辑:每次都去找数组中元素的中间的哪个元素,找到后去和要查找的数字相比,如果比要找的数字小,就往后移动一下,逐渐缩小范围。

代码如下:

#include <stdio.h>
int main()
{
	int arr[16] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//sizeof数组名表示整个数组的大小,
  //除以数组第一个元素的大小得到的就是数组的长度。
	int left = 0;//left存放的是数组左边最小值的下标
	int right = sz - 1;//right存放的是数组右边最大值的下标
	int mid = (left + right) / 2;
  //mid存放的是数组中间的那个数的下标。
	int n = 0;
	scanf("%d", &n);
	while (left <= right)
	{
		if (n > arr[mid])
		{
			mid = left++;
		}
		else if (n < arr[mid])
		{
			mid = right--;
		}
		else
		{
			printf("找到了,数字下表是:%d\n", mid);
			break;
		}
	}
	if (left > right)
	{
		printf("数组中没有这个数字\n");
	}

	return 0;
}

上述代码的逻辑是:

1、声明个数组,定义个存储数组长度的变量sz,sizeof数组名表示整个数组的大小, 除以数组第一个元素的大小得到的就是数组的长度。数组长度sz-1就是数组最大下标的值。

2、然后,定义了三个变量分别是left、right、mid,left存放的是左边数组的下标从下标0开始,right存放的是右边数组的下标,从下标sz-1开始。mid存放的是数组中间数字的下标。

3、然后进入循环体,只有当left<=right的时候,说明这个变量一个在左一个在右,最多两个下标重合,但是如果left都大于right了,说明数组中已经找不到这个元素了。

4、进行判断,arr[mid]代表的就是数组元素,当arr[mid]<n的时候,说明要查找的元素在这个中间元素的右边,所以left++后再赋值给mid,如果,arr[mid]>n,说明要查找的元素在中间元素的左边,所以right--后再赋值给mid。这样一次次的找下去。

5、如果,left>right了,说明数组中没有这个数字。

6、这里需要注意,因为int类型的大小是有上限的,如果,left+right的值超过了这个上限,结果就会有问题。 比如,有两个不一样长的木棍,让我们把他俩变得一样长,是不是可以这样,把长的那根木棍找到和短的木棍一样长的位置做个标记,把剩余的取一半加到短的木棍上去。

C语言二分查找_数组名_03

7、所以我们可以采用下面的方法:mid = left + (right - left) / 2;