一、前言
在一个有序排列的数组中,想要查找到特定数字(k),通常最容易想到的是一个个数组元素查找,但这种方法只适合于数组元素少,特定数字位置比较靠前的数组。如果有大量的数字等待查找,就要寻找更为快速的方法了。下面详细介绍一种C语言常见的查找方法--二分查找。
二、实现思路
三、实现代码
mian主函数内实现:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 7;//要查找的数字
int left = 0;//数组最左边起始位置下标
int right = sz - 1;//数组长度-1=最右边位置下标
int mid = 0;//相加得到的中间元素下标
while (left<=right)
{
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("找不到了\n");
}
}
自定义binary_search函数实现:(注意:函数名要见名知意)
int binary_search(int arr[], int sz, int k)
{
int left = 0;
int right = sz - 1;
int mid = 0;
while (left <= right)
{
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[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 7;
int ret = binary_search(arr, sz, k);
if (ret == -1)
{
printf("找不到\n");
}
else
{
printf("找到了,下标为%d", ret);
}
return 0;
}
代码分析:
- binary_search()需传递三个函数参数:数组名,数组长度,要查找的数字
- 如果找到了,返回查找数字的下标位置
- 如果没有找到,返回-1(数组元素的下标是从0开始的)
运行结果:
四、错误代码示范
int binary_search(int arr[], int k)
{
int left = 0;
//错误代码:
int sz = sizeof(arr) / sizeof(arr[0]);//1
int right = sz - 1;
int mid = 0;
while (left <= right)
{
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[10] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;
int ret = binary_search(arr, k);
if (ret == -1)
{
printf("找不到\n");
}
else
{
printf("找到了,下标为%d", ret);
}
return 0;
}
代码分析:
- 数组arr传参,实际上传递的不是数组本身,而是数组首元素的地址
- 通常用指针变量来存放地址
- 32位平台上指针的大小是4个字节,64位平台上指针的大小是8个字节
- sizeof(arr)/sizeof(arr[0]);计算的是指针/指针-->4/4=1
- binary_search()函数的第一个参数也可以是int* arr
思考:为什么参数传递的是int arr[]或者int* arr而不是int arr[10]?
- 因为传递过去的是数组首元素的地址,为什么要指定大小呢?
- []内指定大小是要开辟一个数组吗?数组都还没有传递过来,为什么要开辟数组?
- 所以,指定大小没有意义,可以不写。
结论:
- 如果函数内部需要参数部分传递某一个数组的元素个数,一定是在函数外部求出该数组的元素个数,再以实参的方式传递给形参。
五、封装函数和导入静态库(了解)
步骤:
- 在该项目工程下新建一个头文件,命名为binary_search.h
- 在该项目工程下新建一个源文件,命名为binary_search.c
- 将函数声明放到binary_search.h,函数具体实现放入binary_search.c
- 右击项目工程-->属性-->常规-->配置类型-->静态库(.lib)
- ctrl + F7 编译代码 ctrl + F5 运行代码
- 在项目工程保存文件下找到Debug文件夹,点击Debug文件夹,找到生成的binary_search.lib
- 新建一个项目工程命名为demo
- 复制binary_search.h和生成的binary_search.lib两个文件到demo工程文件下的demo文件夹下
- 打开demo项目,手动添加头文件binary_search.h
- #pragma comment(lib,"binary_search.lib")放在main主函数之前
- ctrl + F5 运行代码 得到"找到了,下标为6"的打印结果
应用场景:
- 假设自己写出了二分查找的代码,客户A想买这份代码,但是你又想同时卖给客户B。
- 于是只把binary_search.h和binary_search.lib两个文件卖给了客户A
- 二分查找的具体代码还保存在binary_search.c中,也就是说并没有向这两个客户提供源代码
- 客户只能调用这个函数但函数内部如何实现的一无所知