折半查找四要素:
- 查找的内容必须是有序的(升序/降序);
- 每次查找都必须先锁定中间元素;
- 需要查找的元素与中间元素进行比较,从而缩小查找范围;
- 当左下标等于右下标时还未找到,说明要查找的元素不再给定的范围内。
实现整型有序数组的二分查找。(假设需要在整型有序数组 arr[ ] = { 1,2,3,4,5,6,7,8,9,10 } 中查找元素 " 7 " )
简体思路:首先定义一个整型有序数组;然后确定需要查找的元素;再锁定中间元素;用中间元素 与 要查找的元素进行比较,确定要查找的元素所在的范围;改变 左(右)下标,重新锁定中间元素,继续比较,直到 左下标 等于 右下标;如果此时找到了,就返回中间元素下标,如果没找到,说明要查找的元素不再给定范围内。
方法一:
普通代码实现:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // 定义整型有序数组
int key = 7; // 确定要查找的元素
int left = 0; // 数组元素左下标
int mid = 0;
int right = sizeof(arr) / sizeof(arr[0]) - 1; // 数组元素右下标
// 当 左下标 <= 右下标 时进行查找
while (left <= right) {
mid = (left + right) / 2; // 锁定中间元素
// 如果 中间元素 > 要查找的元素,说明要查找的元素在 中间元素的左边,
// 把 右下标 换为 中间元素的 下标减一
if (arr[mid] > key) {
right = mid - 1;
}
// 如果中间元素 < 要查找的元素,说明要查找的元素在 中间元素的右边,
//把 左下标 换为 中间元素的 下标加一
else if (arr[mid] < key) {
left = mid + 1;
}
// 否则退出循环
else {
break;
}
}
// 如果 左下标 <= 右下标 退出,则表示找到了,输出下标
if (left <= right) {
printf("\n找到了,下标是:%d\n", mid);
}
// 如果 左下标 > 右下标 退出,表示找不到。
else {
printf("找不到\n");
}
system("pause");
return 0;
}
代码执行结果:
方法二:
函数实现二分查找。
代码实现:
#include<stdio.h>
#include<stdlib.h>
// 定义 bainary_search 二分查找函数
// 参数:int arr[] --> 整型有序数组
// int k --> 需要查找的元素
// int sz --> 数组大小
int binary_search(int arr[], int k, int sz)
{
int left = 0;
int right = sz;
// 如果 左下标 <= 右下标,则进行比较
while (left <= right) {
int mid = (left + right) / 2; // 锁定中间元素
// 中间元素 与 要查找的元素 进行比较
if (arr[mid] > k)
{
right = mid - 1; //如果中间元素大于要查找的元素,改变右下标
}
else if (arr[mid] == k)
{
return mid; //如果中间元素等于要查找的元素,返回中间元素下标
}
else {
left = mid + 1; //如果中间元素小于要查找的元素,改变左下标
}
}
// 当 左下标 > 右下标 时返回 -1
return -1;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]) - 1; // 数组总大小
int ret = binary_search(arr, 7, sz); // 调用函数,接收函数返回值
if(ret == -1)
{
printf("找不到\n");
}
else {
printf("找到了,下标是:%d\n", ret);
}
system("pause");
return 0;
}
代码执行结果:
注意事项:
1、函数传参时,如果参数是数组,则一定要记住,传过去的是数组首元素的地址。如果函数内部需要用到数组长度,则必须在函数外部计算好该数组的长度,然后以整型进行传参。
2、我们知道,计算两个整型数字的平均数时可以用 这两个数之和除以 2 得到,在计算机中这个方法虽然可行,但当这两个整型数字特别大时,这两个数相加就会出现越界,也就会丢失部分精度,从而造成结果的错误。所以我们可以采用其他的方法求两个数的平均数。
如:较小的数 + (较大的数 - 较小的数)/ 2
对上面锁定中间元素代码改进:
int mid = left + (right - left) / 2; // 改进锁定中间元素