C++算法学习2:二分算法精讲

一、实数二分法回顾

1.1问题背景

在1~2的范围内找到一个x,使得式子5x2 -9x +1 的绝对值<10-9(即无限接近0) 要求:x精确到小数点后9位。

换句话说也就是求:就是求方程 5x2- 9x + 1 =0 在1~2内的近似解

1.2怎么找到这个x呢?

我们需要一个一个试,关键是:试哪些数?

先试边界1和2

将1、2分别带入下列方程

令y = 5x2 - 9x + 1 ,目标:|y| <10-9

得到y=-3、y=3

下一个试谁呢?

将x=1.5带入y = 5x2 - 9x + 1

1.3接下来我们往左边试还是往右边试?

应该往右试:

我们接下来要做的就是反复的左右试题x的值,直到y的绝对值小于10的-9次方为止。

1.4 算法实现

复制代码
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;

int main() {
    double left = 1, right = 2;
    double x = (left + right) / 2;
    double y = 5 * x * x - 9 * x + 1;
    
    while (abs(y) > 1e-9) {
        if (y > 0) right = x;  // 解在左侧
        else left = x;         // 解在右侧
        x = (left + right) / 2;
        y = 5 * x * x - 9 * x + 1;
    }
    
    cout << fixed << setprecision(9) << x;
    return 0;
}

核心特点

  • 终止条件 :解的精度达到 1e-9

  • 区间更新 :直接赋值 left = xright = x

  • 中间值计算:无需考虑整数溢出问题


二、整数二分法解析

猜数字游戏

输入一个范围在 [1, 1000] 内的数字,让计算机去猜,看使用二分法,计算机需要几次就能猜出来:

复制代码
#include<iostream>
using namespace std;
int main(){
    
        int sum=0;//记录一共猜了几次数 
        int b=0,e=1000,x=173;//b,e左边界和右边界确定了数据范围,x=173是我们猜的数字 
         //使用二分法开始猜数 
    while(b<=e){//左边界小于等于右边界是整数二分的条件 
        int mid=(b+e)/2;//获取中间值 
        if(x==mid){
            cout<<"猜对了"<<endl;
            break;
        }
        else if(mid>x){
            cout<<"大了"<<mid<<endl; 
            e=mid-1;//更新右边界值 
            sum++;
        }
        else{
            cout<<"小了"<<mid<<endl; 
            b=mid+1;//更新左边界值 
            sum++;
        }
    }
    cout<<"一共猜了几次"<<sum;        

    return 0;
} 

与实数二分的核心差异

特性 实数二分 整数二分
终止条件 精度达到阈值 left > right
中间值计算 直接取平均 需要处理整数除法特性
区间更新 直接赋值 需要±1操作
内存消耗 浮点运算 整型运算

三、整数二分经典应用

练习:在数组中查找数字3的位置

问题要求

  1. 输入无序数组

  2. 输出首次出现3的位置(从1开始计数)

  3. 不存在时输出-1

实现方案

复制代码
#include <iostream>
#include <algorithm>
using namespace std;

struct Item {
    int id;
    int value;
} a[100];

bool cmp(Item a, Item b) {
    return a.value < b.value;
}

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        a[i].id = i;
        cin >> a[i].value;
    }
    
    // 排序保持原始位置
    sort(a + 1, a + n + 1, cmp);
    
    // 二分查找
    int left = 1, right = n, res = -1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (a[mid].value >= 3) {
            if (a[mid].value == 3) res = a[mid].id;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    
    // 验证是否为首次出现
    if (res != -1) {
        for (int i = right + 1; i <= left; ++i) {
            if (a[i].value == 3) {
                res = min(res, a[i].id);
            }
        }
    }
    
    cout << (res != -1 ? res : -1);
    return 0;
}

关键点解析

  1. 结构体排序:保存原始位置信息

  2. 查找策略

    • 查找第一个≥3的元素

    • 反向扫描确认首次出现位置

  3. 边界处理:处理多个相同值的情况


四、二分算法适用场景

  1. 有序数据集:单调递增/递减序列

  2. 离散数值查找:整数集合中的定位

  3. 分治问题:最大值最小化/最小值最大化问题

  4. 高效查询:时间复杂度O(log n)


五、常见错误及规避

  1. 死循环问题

    • 确保区间更新有进展

    • 使用标准模板:left = mid + 1 / right = mid - 1

  2. 整数溢出

    复制代码
    int mid = left + (right - left) / 2;  // 正确写法
  3. 边界处理

    • 初始化时明确开闭区间

    • 终止条件验证 left <= right


通过系统掌握实数与整数二分法的实现差异,结合经典应用场景的实战训练,可显著提升算法设计能力与代码实现水平。

相关推荐
IT猿手15 分钟前
基于强化学习 Q-learning 算法求解城市场景下无人机三维路径规划研究,提供完整MATLAB代码
神经网络·算法·matlab·人机交互·无人机·强化学习·无人机三维路径规划
万能程序员-传康Kk4 小时前
旅游推荐数据分析可视化系统算法
算法·数据分析·旅游
PXM的算法星球4 小时前
【并发编程基石】CAS无锁算法详解:原理、实现与应用场景
算法
ll7788114 小时前
C++学习之路,从0到精通的征途:继承
开发语言·数据结构·c++·学习·算法
烨然若神人~4 小时前
算法第十七天|654. 最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
算法
爱coding的橙子4 小时前
每日算法刷题Day2 5.10:leetcode数组1道题3种解法,用时40min
算法·leetcode
Akiiiira4 小时前
【数据结构】栈
数据结构
阳洞洞4 小时前
leetcode 18. 四数之和
leetcode·双指针
程序媛小盐5 小时前
贪心算法:最小生成树
算法·贪心算法·图论
Panesle5 小时前
分布式异步强化学习框架训练32B大模型:INTELLECT-2
人工智能·分布式·深度学习·算法·大模型