[C++]二分查找法

版权声明:Copyright © 2018-2018 Takaway 复习用,转载注明一下就行了~ https://blog.csdn.net/LynlinBoy/article/details/84439661

引用:https://baike.baidu.com/item/%E4%BA%8C%E5%88%86%E6%B3%95/1364267?fr=aladdin


二分法

对于区间\boldsymbol{[a,b]}上连续不断且\boldsymbol{f(a)\cdot f(b)< 0}的函数\boldsymbol{y=f(x)},通过不断地把函数\boldsymbol{f(x)}的零点所在的区间一分为二,使区间的两个端点逐步逼近零点,进而得到零点近似值的方法叫二分法。

定义

二分法(Bisection method) 即一分为二的方法. 设\boldsymbol{[a,b]}为R的闭区间. 逐次二分法就是造出如下的区间序列\boldsymbol{([an,bn]):a0=a}\boldsymbol{b0=b},且对任一自然数\boldsymbol{n}\boldsymbol{[an+1,bn+1]}或者等于\boldsymbol{[an,cn]},或者等于\boldsymbol{[cn,bn]},其中\boldsymbol{cn}表示\boldsymbol{[an,bn]}的中点。

典型算法

算法:当数据量很大适宜采用该方法。采用二分法查找时,数据需是排好序的。

基本思想:假设数据是按升序排序的,对于给定值\boldsymbol{key},从序列的中间位置k开始比较,

如果当前位置\boldsymbol{arr[k]}值等于\boldsymbol{key},则查找成功;

\boldsymbol{key}小于当前位置值\boldsymbol{arr[k]},则在数列的前半段中查找,\boldsymbol{arr[low,mid-1]}

\boldsymbol{key}大于当前位置值\boldsymbol{arr[k]},则在数列的后半段中继续查找\boldsymbol{arr[mid+1,high]}

直到找到为止,时间复杂度:\boldsymbol{O(log(n))} 

求法

给定精确度ξ\boldsymbol{\xi},用二分法求函数\boldsymbol{f(x)}零点近似值的步骤如下:

1 确定区间\boldsymbol{[a,b]},验证\boldsymbol{f(a)·f(b)<0},给定精确度\boldsymbol{\xi}.

2 求区间\boldsymbol{(a,b)}的中点\boldsymbol{c}.

3 计算\boldsymbol{f(c)}.

(1) 若\boldsymbol{f(c)=0},则\boldsymbol{c}就是函数的零点;

(2) 若\boldsymbol{f(a)·f(c)<0},则令\boldsymbol{b=c};

(3) 若\boldsymbol{f(c)·f(b)<0},则令\boldsymbol{a=c}.

(4) 判断是否达到精确度\boldsymbol{\xi}:即若\boldsymbol{|a-b|<\xi},则得到零点近似值\boldsymbol{a}(或\boldsymbol{b}),否则重复2-4.


例题

Oj Url:http://noi.openjudge.cn/ch0111/02/

             http://noi.openjudge.cn/ch0111/01/

01:二分法求函数的零点

总时间限制: 1000ms

内存限制: 65536kB

描述

有函数:\boldsymbol{f(x) = x5 - 15 * x4+ 85 * x3- 225 * x2+ 274 * x - 121}

已知 \boldsymbol{f(1.5)>0} , \boldsymbol{f(2.4)<0} 且方程 \boldsymbol{f(x)=0} 在区间 \boldsymbol{[1.5,2,4]} 有且只有一个根,请用二分法求出该根。

输入    无

输出    该方程在区间 \boldsymbol{[1.5,2,4]} 中的根。要求四舍五入到小数点后6位。

样例输入    无

样例输出    不提供

程序代码

#include <iostream>
#include <iomanip>
#include <cmath>
typedef double db;
inline bool determine(const db mid) {
	db f = pow(mid, 5) - 15.0 * pow(mid, 4) + 85.0 * pow(mid, 3) - 225.0 * pow(mid, 2) + 274.0 * mid - 121.0;
	return f > 0.0;	
}; 
int main(int argc, char *argv[]) {
	std::ios::sync_with_stdio(false);
	db left = 1.5, right = 2.4, mid;
	while (right - left > 1e-8) {
		mid = left + (right - left) / 2.0;
		if (determine(mid)) left = mid;
		else right = mid;	
	};
	std::cout << std::fixed << std::setprecision(6) << mid << std::endl;
	return 0;	
};  

 02:查找最接近的元素

总时间限制: 1000ms

内存限制: 65536kB

描述

在一个非降序列中,查找与给定值最接近的元素。

输入

第一行包含一个整数\boldsymbol{n},为非降序列长度。\boldsymbol{1 <= n <= 100000}
第二行包含\boldsymbol{n}个整数,为非降序列各元素。所有元素的大小均在\boldsymbol{0-1,000,000,000}之间。
第三行包含一个整数\boldsymbol{m},为要询问的给定值个数。\boldsymbol{1 <= m <= 10000}
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在\boldsymbol{0-1,000,000,000}之间。

输出

\boldsymbol{m}行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。

样例输入

3
2 5 8
2
10
5

样例输出

8
5

程序代码

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
const int INF = 0x3ffffff;
const int MAX_SIZE = 1000001;
int array[MAX_SIZE] = {};
template <typename _Tp>
inline void quicksort(_Tp *arr, int start, int end) {
	int i = start, j = end; _Tp pivot = arr[start];
	if (i >= j) return;
	while (i != j) {
		while (i < j && arr[j] > pivot) --j;
		while (i < j && arr[i] < pivot) ++i;
		if (i < j) swap(arr[i], arr[j]);	
	};	
	swap(arr[i], arr[start]);
	quicksort(arr, start, i - 1);
	quicksort(arr, i + 1, end);
};
int main(int argc, char *argv[]) {
	int n; cin >> n;
    for (int i = 0; i < n; ++i) scanf("%d", array + i);
	int m; cin >> m;
    while (m--) {
        int bf, answer, left = 0, mid, right = n - 1; cin >> bf;
        if (bf <= array[0]) {cout << array[0] << endl; continue;};
        if (bf >= array[n - 1]) {cout << array[n - 1] << endl; continue;};
        while (left <= right) {
            mid = left + (right - left) / 2;
            if(array[mid] <= bf) left = mid + 1;
            else right = mid - 1;
        };
        if (abs(array[left] - bf) < abs(array[right] - bf)) answer = left;
        else answer = right;	
        cout << array[answer] << endl;
    };
    return 0;
};

猜你喜欢

转载自blog.csdn.net/LynlinBoy/article/details/84439661