二分查找(折半查找)
时间复杂度:O(logN), 以2为底
前提:单调序列,编写代码需已知单增或单减
终止条件: head > tail
循坏条件: head <= tail
待查找元素:x,仅仅是找到数x是否存在该数组中,返回下标值, 如果数组中出现相同元素,二分查找是随机找到一个即可,返回下标。
描述:head指向头部,tail指向尾部,每次劈一半(扔掉)
标准版二分查找
#include <stdio.h>
# 实现在一个数组arr中查找元素x是否存在,数组长度为len,若找到x,返回x数组下标,否则返回-1
int binary_search(int *arr, int len, int x) {
int head = 0, tail = len - 1, mid;
while (head <= tail) {
mid = (head + tail) >> 1;
if (arr[mid] == x) return mid;
if (arr[mid] < x) head = mid + 1; // 假设单调递增
else tail = mid - 1;
}
return -1;
}
int main() {
#define MAX_N 100
int num[MAX_N + 5], n, x;
scanf("%d", &n); // 数组长度n
for (int i = 0; i < n; i++) {
scanf("%d\n", (num + i));
} // 键入n个数据
while (~scanf("%d", &x)) {
printf("%d\n", binary_search(num, n, x));
} // 循坏读入,待判断的x
#undef MAX_N
return 0;
}
7 // 数据长度n
1 3 5 7 9 10 12 // 数组的n个元素
1 // 待判断查找的x
0 // 返回的下标
3
1
10
5
13
-1
递归版二分查找
#include <stdio.h>
// 递归版二分法
int binary_search(int *arr, int head, int tail, int x) {
if (head > tail) return -1;
int mid = (head + tail) >> 1;
if (arr[mid] == x) return mid;
if (arr[mid] < x) head = mid + 1;
else tail = mid - 1;
return binary_search(arr, head, tail, x);
}
int main() {
#define MAX_N 100
int num[MAX_N + 5], n, x;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d\n", (num + i));
}
while (~scanf("%d", &x)) {
printf("%d\n", binary_search(num, 0, n - 1, x));
}
#undef MAX_N
return 0;
}
arr( ) 函数 y = f ( x ) , x 与 y 一一对应,映射关系。
arr[ ] 数组 arr[4] = 2 , 数组的下标索引与值也一一对应。
函数是压缩的数组,数组是展开的函数。
用二分法查找设计开平方根
#include <stdio.h>
#include <math.h>
double func(double n) {
return n * n;
}
double binary_search(double (*arr)(double), double x) {
double head = 0, tail = x, mid;
if (x < 1) tail = 1.0;
#define EE 1e-7
while (head < tail) {
mid = (head + tail) / 2.0;
if (fabs(arr(mid) - x) < EE) return mid;
if (arr(mid) < x) head = mid;
else tail = mid;
}
#undef EE
return -1;
}
int main() {
double x;
while (~scanf("%lf", &x)) {
printf("my_sqrt(%g) = %g\n", x, binary_search(func, x));
printf("sqrt(%g) = %g\n", x, sqrt(x));
}
return 0;
}
>>10
>my_sqrt(10) = 3.16228
>sqrt(10) = 3.16228
>>1
>my_sqrt(1) = 1
>sqrt(1) = 1
>>4
>my_sqrt(4) = 2
>sqrt(4) = 2
>>0.1
>my_sqrt(0.1) = 0.316228
>sqrt(0.1) = 0.316228
二分法习题:方程x*e^x = a,输入a;输出一个浮点数,表示方程的解,四舍五入到小数点后四位
样例
0
>> 0.0000
1
>>0.5671
100
>3.3856
二分法习题
// x * e^x = a
#include <stdio.h>
#include <math.h>
double func(double x) {
return x * exp(x);
}
double binary_search(double (*arr)(double), int a) {
double head = 0, tail = a, mid;
#define EE 1e-7
while (fabs(head - tail) > EE) {
mid = (head + tail) / 2.0;
if (fabs(arr[mid] - a) < EE) return mid;
if (arr(mid) < a) head = mid;
else tail = mid;
}
#undef EE
return head;
}
int main() {
double a;
while (~scanf("%d", &a)) {
printf("%.4lf\n", binary_search(func, a));
}
return 0;
}
二分查找特殊情况: 1 1 1 1 0 0 0 0 0 0 找出最后一个满足要求的数的位置
#include <stdio.h>
int binary_search(int *arr, int n) {
int head = -1, tail = n - 1, mid;
while (head < tail) {
mid = (head + tail + 1) >> 1;
if (arr[mid] == 0) tail = mid - 1;
else head = mid;
}
rerurn head;
}
int main() {
int arr[10] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0};
printf("%d\n", binary_search(arr, 10));
return 0;
}
报数题