C语言————二分法

在 C++ 中,二分法(Binary Search)是一种用于在有序数组中查找特定元素的高效算法。

基本原理:

二分法的核心思想是利用数组的有序性,每次将搜索区间缩小一半。它通过比较目标值与区间中间元素的值来决定下一步的搜索方向,直到找到目标值或者确定目标值不存在于数组中。

例如【1,2,3】我们查找3,mid(一半的位置,也可以叫中间位置)是2,并且2<3,如果3存在于数组中,那一定在2的右边(此过程中我们将数组均匀的一分为二,并找出目标值可能存在的那一半,然后舍弃另一半),这是让区间缩小,左边界改为mid+1(或者mid)重新查找并找到了3.

在中学数学中,曾使用二分法寻找0点,也是使用分割区间的方法来寻找0点可能存在的子区间。

算法步骤:
  1. 初始化:设置两个指针,left 和 right,分别指向数组的起始位置和结束位置。

  2. 计算中间位置:在每次循环中,计算中间位置 mid,通常使用公式 mid = left + (right - left) / 2。(本质上还是(l+r)/2,先多减再回加可以避免l+r过大的情况)这样可以避免 left 和 right 相加时可能出现的溢出问题。

  3. 比较中间元素与目标值

  • 如果中间元素 arr[mid] 等于目标值 target,则表示找到了目标,返回 mid
  • 如果 arr[mid] 大于 target,说明目标值在左半部分,更新 right = mid - 1,继续在左半区间搜索。
  • 如果 arr[mid] 小于 target,说明目标值在右半部分,更新 left = mid + 1,继续在右半区间搜索。

4.循环执行:重复步骤 2 和 3,直到 left 大于 right,此时表示目标值不在数组中,返回 -1 或其他表示未找到的标识。

代码实现:

  迭代实现:
int binarySearch(int arr[], int left, int right, int target) {
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {
            return mid;  // 找到目标元素,返回其索引
        } else if (arr[mid] < target) {
            left = mid + 1;  // 目标元素在右半部分
        } else {
            right = mid - 1;  // 目标元素在左半部分
        }
    }
    return -1;  // 未找到目标元素
}
递归实现:
int binarySearchRecursive(int arr[], int left, int right, int target) {
    if (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {
            return mid;  // 找到目标元素,返回其索引
        } else if (arr[mid] < target) {
            return binarySearchRecursive(arr, mid + 1, right, target);  // 目标元素在右半部分
        } else {
            return binarySearchRecursive(arr, left, mid - 1, target);  // 目标元素在左半部分
        }
    }
    return -1;  // 未找到目标元素
}
总代码举例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int binarySearch(vector<int>& arr, int target) {
    int left = 0;
    int right = arr.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {return mid;}
        else if (arr[mid] > target) {right = mid - 1;}
        else {left = mid + 1;}
    }
    return -1;
}
int main() {
    vector<int> arr = {1, 3, 5, 29, 7, 9, 11, 13, 15};
    sort(arr.begin(), arr.end());//从小到大排序
    int target = 7;
    int result = binarySearch(arr, target);
    cout << result << endl;
    return 0;
}

算法分析:

复杂度分析

复杂度:
  • 时间复杂度:二分法每次迭代都将搜索区间减半,因此时间复杂度为 O(log n),其中 n是数组的元素数量。这使得二分法在处理大规模有序数据时非常高效。
  • 空间复杂度:在基本的二分法实现中,只需要几个额外的变量来跟踪搜索区间,因此空间复杂度为 O(1)。

O(log n)的由来:这个查找过程会一直持续,也就会一直除以2,直到我们找到目标元素或者确定目标元素不存在于数组中。当查找范围缩小到只剩下 1 个元素时,就不能再继续二分了,此时可以认为查找结束。即当\frac{n}{2^{k}}=1时,查找过程停止。 n=2^{k},k=log_{2}n所以二分法的时间复杂度就表示为O(log n)。

应用场景:

  • 在有序数组中查找元素:这是二分法最常见的应用,快速确定某个元素是否存在于数组中,并获取其位置。

  • 求解方程的根:通过不断缩小根所在的区间范围,逼近方程的解。

  • 优化问题:例如在寻找最优解的过程中,通过二分搜索来逐步缩小可能的解空间。

通过改变mid是>=还是>(或者<=和<)在解决存在多个相同的目标值的问题时可以改变mid最终是在这一组目标值的左边还是右边 。

二分基础练习题:洛谷P2249

posted @ 2025-01-27 08:00  mc12356  阅读(25)  评论(0)    收藏  举报  来源