突破编程_C++_查找算法(插值查找)

1 算法题 :使用插值查找算法在有序数组中查找指定元素

1.1 题目含义

使用插值查找算法在有序数组中查找指定元素。插值查找是介于线性查找和二分查找之间的一种查找算法,它是基于二分查找的改进算法。插值查找的核心思想在于根据待查找元素的值在有序数组中的位置,利用数学公式计算出该元素在数组中的大致位置,从而缩小查找范围,提高查找效率。

1.2 示例

示例 1:

输入:

  • nums = [1, 3, 4, 7, 10, 12, 13, 16, 18, 20]
  • target = 7

输出: 3
说明: 7 存在于 nums 中,且其索引为 3。

示例 2:

输入:

  • nums = [1, 3, 4, 7, 10, 12, 13, 16, 18, 20]
  • target = 25

输出: -1
说明: 25 不存在于 nums 中,返回 -1。

示例 3:

输入:

  • nums = []
  • target = 0

输出: -1
说明: nums 为空,0 不存在于 nums 中,返回 -1。

2 解题思路

2.1 循环遍历实现

(1)初始化参数:

  • 确定有序数组 arr 和待查找元素 target。
  • 获取数组的长度 n。
  • 设置数组的起始索引 low 为 0,结束索引 high 为 n - 1。

(2)检查边界情况:

  • 如果 target 小于 arr[low] 或大于 arr[high],则 target 不在数组中,直接返回 -1。

(3)计算插值位置:

  • 使用插值公式计算 target 在数组中的大致位置 pos。插值公式通常如下:
pos = low + ((target - arr[low]) * (high - low) / (arr[high] - arr[low]))
  • 确保 pos 是一个合法的索引值,即它应在 low 和 high 之间。如果 pos 不合法,则将其限制在合法范围内。

(4)缩小查找范围(比较 arr[pos] 与 target):

  • 如果它们相等,返回 pos,因为找到了目标元素。
  • 如果 target 小于 arr[pos],则新的结束索引 high 更新为 pos - 1。
  • 如果 target 大于 arr[pos],则新的起始索引 low 更新为 pos + 1。

(5)循环查找:

  • 使用一个循环来重复上述步骤,直到找到目标元素或查找范围为空。
  • 在每次循环中,重新计算插值位置 pos 并根据比较结果更新查找范围。

(6)返回结果:

  • 如果在循环结束前找到了 target,则返回其索引。
  • 如果循环结束后仍未找到 target(即 low 大于 high),则返回 -1,表示 target 不在数组中。

2.2 递归实现

(1)初始化参数:

  • 确定有序数组 arr 和待查找元素 target。
  • 获取数组的长度 n。
  • 设置数组的起始索引 low 为 0,结束索引 high 为 n - 1。

(2)检查边界情况:

  • 如果 target 小于 arr[low] 或大于 arr[high],则 target 不在数组中,直接返回 -1。

(3)递归函数定义:

  • 定义一个递归函数 interpolationSearchRecursive,该函数接受当前查找范围的起始索引 low、结束索引 high、目标值 target 和数组 arr 作为参数。

(4)计算插值位置:

  • 使用插值公式计算 target 在数组中的大致位置 pos。插值公式通常如下:
pos = low + ((target - arr[low]) * (high - low) / (arr[high] - arr[low]))
  • 确保 pos 是一个合法的索引值,即它应在 low 和 high 之间。如果 pos 不合法,则将其限制在合法范围内。

(5)递归调用(比较 arr[pos] 与 target):

  • 如果它们相等,返回 pos,因为找到了目标元素。
  • 如果 target 小于 arr[pos],则在数组的左半部分(low 到 pos - 1)继续递归查找。
  • 如果 target 大于 arr[pos],则在数组的右半部分(pos + 1 到 high)继续递归查找。
  • 递归调用 interpolationSearchRecursive 函数,传入更新后的查找范围和目标值。

(6)递归终止条件:

  • 找到了目标元素,返回其索引。
  • 查找范围为空(即 low 大于 high),表示目标元素不在数组中,返回 -1。

(7)返回结果:

  • 根据递归函数返回的结果,输出目标元素是否存在于数组中以及它的索引。

3 算法实现代码

3.1 循环遍历实现

如下为算法实现代码:

#include <iostream>  
#include <string>  
#include <vector>  

class Solution
{
public:
	int interpolationSearch(std::vector<int>& nums, int target) {
		int n = arr.size();  
    if (n <= 0) {  
        return -1;  // 空数组,返回-1  
    }  
  
    int low = 0, high = n - 1;  
  
    // 检查边界情况  
    if (target < arr[low] || target > arr[high]) {  
        return -1;  // 目标值不在数组范围内  
    }  
  
    while (low <= high && arr[low] <= target && arr[high] >= target) {  
        // 计算插值位置  
        int pos = low + static_cast<int>(  
            ((double)(high - low) / (arr[high] - arr[low]) * (target - arr[low]));  
  
        // 检查pos是否越界  
        if (pos < low || pos > high) {  
            pos = (pos < low) ? low : high;  
        }  
  
        // 比较arr[pos]与目标值  
        if (arr[pos] == target) {  
            return pos;  // 找到目标值,返回其索引  
        }  
  
        // 根据比较结果更新查找范围  
        if (arr[pos] < target) {  
            low = pos + 1;  
        } else {  
            high = pos - 1;  
        }  
    }  
  
    // 没有找到目标值  
    return -1;  
	}
};

这段代码首先检查数组的边界情况,然后进入一个循环,在循环中计算插值位置,并根据比较结果更新查找范围。循环会一直执行,直到找到目标元素或确定目标元素不在数组中。最后,返回找到的元素的索引或-1表示未找到。

调用上面的算法,并得到输出:

int main() 
{
	Solution s;

	std::vector<int> arr = { 1, 3, 4, 7, 10, 12, 13, 16, 18, 20 };
	int target = 7;
	int index = s.interpolationSearch(arr, target);
	if (index != -1) {
		std::cout << "Element " << target << " found at index: " << index << std::endl;
	}
	else {
		std::cout << "Element " << target << " not found in the array." << std::endl;
	}

	return 0;
}

上面代码的输出为:

Element 7 found at index: 3

3.2 递归实现

如下为算法实现代码:

#include <iostream>  
#include <string>  
#include <vector>  

class Solution
{
public:
	int interpolationSearch(std::vector<int>& nums, int target) {
		return interpolationSearchRecursive(nums, target, 0, nums.size() - 1);
	}

private:
	int interpolationSearchRecursive(const std::vector<int>& nums, int target, int low, int high) {
		// 检查边界情况  
		if (low > high || target < nums[low] || target > nums[high]) {
			return -1;  // 目标值不在数组范围内  
		}

		if (low == high) {
			return (nums[low] == target) ? low : -1;  // 如果low和high相等,检查是否找到目标值  
		}

		// 计算插值位置  
		int pos = low + static_cast<int>(
			((double)(high - low) / (nums[high] - nums[low]) * (target - nums[low])));

		// 确保pos是合法索引  
		pos = (pos < low) ? low : (pos > high) ? high : pos;

		// 比较nums[pos]与目标值  
		if (nums[pos] == target) {
			return pos;  // 找到目标值,返回其索引  
		}
		else if (nums[pos] < target) {
			return interpolationSearchRecursive(nums, target, pos + 1, high);  // 在右半部分递归查找  
		}
		else {
			return interpolationSearchRecursive(nums, target, low, pos - 1);  // 在左半部分递归查找  
		}
	}
};

在这段代码中,interpolationSearchRecursive 成员函数函数是递归查找的主体,它接受数组 nums、目标值 target、当前查找范围的起始索引 low 和结束索引 high 作为参数。函数首先检查边界情况,然后计算插值位置,并递归地在左半部分或右半部分查找,直到找到目标值或确定目标值不在数组中。interpolationSearch 函数是外部调用接口,它初始化了查找范围并调用了递归函数。

4 测试用例

以下是针对上面算法的测试用例,基本覆盖了各种情况:

(1)基础测试用例
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 9
输出:4
说明:目标值 9 存在于数组中,位于索引 4 的位置。

(2)目标值不存在于数组中
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 2
输出:-1
说明:目标值 2 不存在于数组中。

(3)目标值位于数组开头
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 -1
输出:0
说明:目标值 -1 位于数组的开头,即索引 0 的位置。

(4)目标值位于数组末尾
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 12
输出:5
说明:目标值 12 位于数组的末尾,即索引 5 的位置。

(5)目标值位于数组中间
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 3
输出:2
说明:目标值 3 位于数组的中间位置,即索引 2 的位置。

(6)空数组
输入:数组 [],目标值 9
输出:-1
说明:空数组不包含任何元素,因此无法找到目标值。

(7)数组只有一个元素
输入:数组 [9],目标值 9
输出:0
说明:数组只有一个元素,且该元素就是目标值,位于索引 0 的位置。

(8)数组中存在多个相同的目标值
输入:数组 [1, 2, 3, 3, 4, 5],目标值 3
输出:2 或 3
说明:数组中存在多个目标值 3,返回任意一个目标值的索引都是正确的。这里可以返回 2 或 3。

相关推荐

  1. 突破编程_C++_查找算法查找

    2024-03-17 03:52:01       25 阅读
  2. 突破编程_C++_查找算法(二分查找

    2024-03-17 03:52:01       22 阅读
  3. 突破编程_C++_查找算法(分块查找

    2024-03-17 03:52:01       14 阅读
  4. 突破编程_C++_查找算法(二叉树查找

    2024-03-17 03:52:01       20 阅读
  5. python查找

    2024-03-17 03:52:01       33 阅读
  6. c语言查找算法

    2024-03-17 03:52:01       42 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-17 03:52:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-17 03:52:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-17 03:52:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-17 03:52:01       18 阅读

热门阅读

  1. 稳定币套利案例解析一 两个疑点

    2024-03-17 03:52:01       20 阅读
  2. 【Python学习笔记】Python近期总结

    2024-03-17 03:52:01       19 阅读
  3. 24计算机考研调剂 | 哈尔滨理工大学

    2024-03-17 03:52:01       22 阅读
  4. CentOS7下使用Dockers安装MinIO

    2024-03-17 03:52:01       16 阅读
  5. 【面经&八股】搜广推方向:面试记录(八)

    2024-03-17 03:52:01       19 阅读
  6. 程序员如何选择职业赛道

    2024-03-17 03:52:01       16 阅读
  7. LeetCode -- 76. 最小覆盖子串

    2024-03-17 03:52:01       18 阅读
  8. 前端如何识别上传的二维码---jsQR

    2024-03-17 03:52:01       18 阅读
  9. 计算机安全

    2024-03-17 03:52:01       17 阅读
  10. MySQL 中的锁机制详解

    2024-03-17 03:52:01       19 阅读
  11. transformer注意力权重系数绘图

    2024-03-17 03:52:01       18 阅读
  12. vue数据

    vue数据

    2024-03-17 03:52:01      14 阅读