29 C++ 算法2-查找

C++ 算法2-查找

1. 线性查找(顺序查找/遍历查找)

1. 算法:从表头开始,依次将每一个值与目标元素进行比较,直到找到或者找不到为止。
2. 评价:平均时间复杂度O(N),对样本的有序性没有要求。

2. 二分查找(折半查找)

  1. 算法:首先,假设表中的元素按升序排列,将表的中间元素与查找目标比较,如果相等则查找成功,如果中间元素>查找目标则在中间元素的左侧子表中继续查找,否则在中间元素的右侧子表中继续查找。重复以上过程,直到找到满足条件的元素为止——查找成功,或子表不存在——查找失败。

    • 核心思想:通过比较中间元素 data[mid] 与目标值 key,逐步缩小搜索范围。
  2. 评价:平均时间复杂度O(logN),要求样本必须有序。

3. 示例程序

// 查找算法
#include <iostream>
using namespace std;
// 线性查找
int line (int data[], int size, int key) {
    for (int i = 0; i < size; i++)
        if (data[i] == key)
            return i;
    return -1;
}

// 二分查找(迭代实现)
// 参数:
//   data[]: 已排序的数组 
//   size: 数组长度 
//   key: 要查找的目标值 
// 返回值:
//   找到时返回目标值的索引,未找到时返回-1 
int binary (int data[], int size, int key) {
    int left = 0;           // 初始化左边界为数组起始位置 
    int right = size - 1;   // 初始化右边界为数组末尾位置 

    // 当左边界不超过右边界时循环 
    while (left <= right) {
        int mid = (left + right) / 2; // 计算中间位置 

        if (key < data[mid])// 目标值在左半部分 
            right = mid - 1;// 调整右边界 
        else
        if (key > data[mid])// 目标值在右半部分 
            left = mid + 1;  // 调整左边界 
        else
            return mid;    // 找到目标值 
    }
    return -1;  // 未找到目标值 
}

// 二分查找(递归实现)
// 参数:
//   data[]: 已排序的数组 
//   left: 当前查找范围的左边界 
//   right: 当前查找范围的右边界 
//   key: 要查找的目标值 
// 返回值:
//   找到时返回目标值的索引,未找到时返回-1 
int binary (int data[], int left,int right,int key){

    // 递归终止条件:左边界超过右边界 
    if (left > right)
        return -1;

    int mid = (left + right) / 2;// 计算中间位置 

    if (key < data[mid])           // 目标值在左半部分 
        return binary (data, left, mid - 1, key); // 递归查找左半部分 
    else
    if (key > data[mid])           // 目标值在右半部分 
        return binary (data, mid + 1, right, key);// 递归查找右半部分 
    else
        return mid;   // 找到目标值 
}

int main (void) {
    int data[] = {13, 23, 44, 26, 77, 52, 8};
    int size = sizeof (data) / sizeof (data[0]);
//    int res = line (data, size, 26);
//    int res = line (data, size, 55);
    int data2[] = {8, 13, 23, 26, 44, 52, 77};
    size = sizeof (data2) / sizeof (data2[0]);
//    int res = binary (data2, size, 26);
//    int res = binary (data2, size, 55);
//    int res = binary (data2, 0, size - 1, 77);
    int res = binary (data2, 0, size - 1, 0);
    if (res == -1)
        cout << "不存在" << endl;
    else
        cout << "找到了:" << res << endl;
    return 0;
}

迭代 vs 递归

特性迭代实现递归实现
空间复杂度O(1)(无需额外空间)O(log n)(递归调用栈)
适用场景大规模数据(避免栈溢出)小规模数据(代码更简洁)
性能通常更快(无函数调用开销)稍慢(递归调用有额外开销)

4 二分查找的变种及其应用场景

​ 二分查找的核心思想是通过分治策略快速定位目标值,但在实际应用中,可能需要处理重复值、边界条件或非精确匹配等问题。

1. 查找第一个等于目标值的位置

问题:数组中有多个 target,返回第一个出现的位置。
示例:[1, 2, 2, 2, 3] 中查找 2,应返回索引 1

int binary_search_first(int arr[], int size, int target) {

    int left = 0, right = size - 1;

    while (left <= right) {

        int mid = left + (right - left) / 2;

        if (arr[mid] >= target) {
            right = mid - 1; // 继续向左查找 
        } 
        else {
            left = mid + 1;
        }
    }
    if (left < size && arr[left] == target) return left;

return -1;
}

2. 查找最后一个等于目标值的位置

问题:返回最后一个 target 的位置。
示例:[1, 2, 2, 2, 3] 中查找 2,应返回索引 3

int binary_search_last(int arr[], int size, int target) {

    int left = 0, right = size - 1;
    while (left <= right) {

        int mid = left + (right - left) / 2;
        if (arr[mid] <= target) {
            left = mid + 1; // 继续向右查找 
        } 
        else {
            right = mid - 1;
        }
    }
    if (right >= 0 && arr[right] == target) return right;
    return -1;
}

#3# 3. 查找第一个大于等于目标值的位置

问题:返回第一个≥ target的元素位置(可用于插入位置)。
示例:[1, 3, 5, 7] 中查找 4,应返回索引 25 的位置)。

int binary_search_first_gte(int arr[], int size, int target) {
    int left = 0, right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] >= target) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return left; // 注意:可能返回 size(表示所有元素均小于 target)
}

4. 查找最后一个小于等于目标值的位置

问题:返回最后一个 ≤ target 的元素位置。
示例:[1, 3, 5, 7] 中查找 4,应返回索引 13 的位置)。

int binary_search_last_lte(int arr[], int size, int target) {
    int left = 0, right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] <= target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return right; // 注意:可能返回 -1(表示所有元素均大于 target)
}

5. 旋转有序数组中的查找

问题:在旋转后的有序数组(如 [4, 5, 6, 1, 2, 3])中查找目标值。
关键点:先找到旋转点,再在左右半部分分别二分查找。
示例: 找到 4,位置在索引 0 ,找到 6,位置在索引 2

int search_in_rotated_array(int arr[], int size, int target) {
    int left = 0, right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) return mid;
        // 判断左右哪一部分有序 
        if (arr[left] <= arr[mid]) { // 左半部分有序 
            if (arr[left] <= target && target < arr[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        } else { // 右半部分有序 
            if (arr[mid] < target && target <= arr[right]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }
    return -1;
}

6. 查找峰值元素

问题:在无序数组中找到任意一个峰值(比相邻元素大)。
示例:[1, 3, 20, 4, 1] 的峰值是 204

int find_peak_element(int arr[], int size) {
    int left = 0, right = size - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] < arr[mid + 1]) {
            left = mid + 1; // 峰值在右侧 
        } else {
            right = mid; // 峰值在左侧 
        }
    }
    return left; // 返回任意一个峰值的位置 
}

7. 查找缺失的数字

问题:在 [0, 1, 3, 4] 中找到缺失的数字(如 2)。
变种:数组按升序排列,且唯一缺失一个数字。

int find_missing_number(int arr[], int size) {
    int left = 0, right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == mid) {
            left = mid + 1; // 缺失在右侧 
        } else {
            right = mid - 1; // 缺失在左侧 
        }
    }
    return left; // 返回缺失的数字 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值