SXSBJSXYT

保持热爱,奔赴山海

 

二分查找法

1.概念

        假如现在有1~100个数,你的目标是以最少的次数猜到这个数字。你每次猜测后,我会说小了、大了或猜对了。假设你从1开始依次往上猜,猜测过程可能会是这样。

        这是最简单的查找方法,更准确的说法是傻找。每次猜测都只能排除一个数字。如果我想的数字是99, 你得猜99次才能猜到!

        下面是一种更佳的猜法。从50开始。

        虽然猜小了,但排除了一半的数字!至此,你知道1~50都小了。接下来,你猜75。

        这次猜大了,那余下的数字又排除了一半!使用二分查找时,你猜测的是中间的数字,从而每次都将余下的数字排除一半。接下来,你猜63(50和75中间的数字)。

        这就是二分查找,每次猜测排除的数字个数如下。

        一般而言,对于包含n个元素的列表,用二分查 找最多需要log2n步,而简单查找最多需要n步。

2.代码示例

2.1 C代码

#include <stdio.h>

/**
 * 二分查找函数(适用于升序数组)
 * @param arr 已排序的整型数组
 * @param len 数组长度
 * @param target 目标查找值
 * @return 目标值在数组中的索引(从0开始),未找到返回-1
 */
int binary_search(int arr[], int len, int target) {
    int left = 0;              // 左边界索引
    int right = len - 1;       // 右边界索引
    int mid = 0;

    while (left <= right) {    // 左闭右闭区间 [left, right]
         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 main() {
    // 示例测试
    int test_array[] = { 2, 5, 8, 12, 16, 23, 38, 45, 56, 72 };
    int length = sizeof(test_array) / sizeof(test_array[0]);

    // 测试用例
    printf("查找 23:索引=%d\n", binary_search(test_array, length, 23)); // 应返回5
    printf("查找 45:索引=%d\n", binary_search(test_array, length, 45)); // 应返回7
    printf("查找 3:索引=%d\n", binary_search(test_array, length, 3));  // 应返回-1

    return 0;
}

var code = "d02689ab-53ef-483a-bb8f-713588e7a47b"

2.2 示例代码注意项

         在二分查找或类似算法中,计算中间索引 mid 时,使用 int mid = left + (right - left) / 2; 而不是直接 int mid = (left + right) / 2;,主要是为了防止整数溢出。

        备注:直接写法的风险:(left + right) / 2,当 left 和 right 都是较大的正整数时(接近 INT_MAX),left + right 可能会超过 int 类型的最大值(例如 INT_MAX = 2,147,483,647),导致整数溢出

int left = 2000000000;
int right = 2100000000;
int mid = (left + right) / 2; // left + right = 4,100,000,000 > INT_MAX,溢出为负数!

3.在嵌软开发中的应用

        在嵌入式系统中,二分法(二分查找、二分逼近)因其高效的 O(log n) 时间复杂度和低内存开销,被广泛应用于资源受限的场景。

  • 应用场景:嵌入式设备中常存储静态配置表(如传感器校准表、PT1000温度-电阻对照表、酒精密度与温度对照表等)。

  • 代码示例

// 温度-ADC值对照表(按温度升序排列)
const struct { float temp; uint16_t adc; } calib_table[] = {
    {-10, 100}, {0, 250}, {25, 500}, {50, 750}, {100, 1000}
};

// 二分法查找ADC值对应的温度
float adc_to_temp(uint16_t adc_val) {
    int left = 0, right = sizeof(calib_table)/sizeof(calib_table[0]) - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (calib_table[mid].adc == adc_val) {
            return calib_table[mid].temp;
        } else if (calib_table[mid].adc < adc_val) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1.0f; // 未找到
}
  • 优势:比线性查找更快,适合实时性要求高的场景。

3.1总结

        二分法在嵌入式领域的核心优势是 高效+低资源消耗,尤其适合实时性要求高的场景、资源受限的系统(如MCU仅有几KB内存)、需要快速检索静态数据的应用。通过合理设计,可以显著提升嵌入式系统的性能和响应速度。

posted on 2025-04-15 17:36  SXSBJSXYT  阅读(14)  评论(0)    收藏  举报  来源

导航